2024-03-19 00:02:11 +00:00
|
|
|
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, "");
|
|
|
|
}
|
|
|
|
|
2024-03-19 02:39:13 +00:00
|
|
|
const n=x=>null;
|
|
|
|
|
2024-03-19 00:02:11 +00:00
|
|
|
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");
|
2024-03-19 17:30:37 +00:00
|
|
|
const el_id_submitwhoamiManual = document.querySelector("#submitwhoami_manual");
|
2024-03-19 00:02:11 +00:00
|
|
|
const el_id_errorwhoami = document.querySelector("#errorwhoami");
|
2024-03-19 17:30:37 +00:00
|
|
|
let gamemodeFollowers = "";
|
2024-03-19 00:02:11 +00:00
|
|
|
|
|
|
|
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;
|
2024-03-19 02:39:13 +00:00
|
|
|
|
|
|
|
// webfinger domain delegation
|
|
|
|
const domain = await fetch(`https://${instance}/.well-known/webfinger?resource=acct:${username}@${instance}`).catch(n);
|
2024-03-19 02:43:35 +00:00
|
|
|
if (domain == null || !domain.ok) return null;
|
2024-03-19 02:39:13 +00:00
|
|
|
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);
|
2024-03-19 02:43:35 +00:00
|
|
|
if (user_req == null || !domain.ok) return null;
|
2024-03-19 00:02:11 +00:00
|
|
|
const user_json = await user_req.json();
|
2024-03-19 15:08:44 +00:00
|
|
|
|
|
|
|
window.localStorage.setItem("fediversemadness_game", JSON.stringify({ username, instance }));
|
2024-03-19 02:39:13 +00:00
|
|
|
|
|
|
|
return {
|
2024-03-19 00:02:11 +00:00
|
|
|
USER_ID: user_json.id,
|
2024-03-19 02:39:13 +00:00
|
|
|
INSTANCE: domain_url
|
2024-03-19 00:02:11 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-03-19 15:08:44 +00:00
|
|
|
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();
|
|
|
|
|
2024-03-19 17:30:37 +00:00
|
|
|
async function doVerif() {
|
2024-03-19 02:26:02 +00:00
|
|
|
el_id_submitwhoamiFollowers.disabled = true;
|
|
|
|
el_id_submitwhoamiFollowing.disabled = true;
|
2024-03-19 17:30:37 +00:00
|
|
|
el_id_submitwhoamiManual.disabled = true;
|
2024-03-19 15:08:44 +00:00
|
|
|
game = await verify();
|
2024-03-19 02:26:02 +00:00
|
|
|
el_id_submitwhoamiFollowers.disabled = false;
|
|
|
|
el_id_submitwhoamiFollowing.disabled = false;
|
2024-03-19 17:30:37 +00:00
|
|
|
el_id_submitwhoamiManual.disabled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
el_id_submitwhoamiFollowers.addEventListener("click", async (e) => {
|
|
|
|
el_id_errorwhoami.innerHTML = "";
|
|
|
|
await doVerif();
|
2024-03-19 15:08:44 +00:00
|
|
|
if (game == null) {
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_errorwhoami.innerHTML = "Invalid user!";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-03-19 17:30:37 +00:00
|
|
|
gamemodeFollowers = "followers";
|
|
|
|
startFollowers();
|
2024-03-19 00:02:11 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
el_id_submitwhoamiFollowing.addEventListener("click", async (e) => {
|
|
|
|
el_id_errorwhoami.innerHTML = "";
|
2024-03-19 17:30:37 +00:00
|
|
|
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();
|
2024-03-19 15:08:44 +00:00
|
|
|
if (game == null) {
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_errorwhoami.innerHTML = "Invalid user!";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-03-19 17:30:37 +00:00
|
|
|
gamemodeFollowers = "manual";
|
|
|
|
startManual();
|
2024-03-19 00:02:11 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
// 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");
|
2024-03-19 15:08:44 +00:00
|
|
|
const el_id_savehandlesfollowers = document.querySelector("#savehandlesfollowers");
|
|
|
|
const el_id_loadhandlesfollowers = document.querySelector("#loadhandlesfollowers");
|
2024-03-19 00:02:11 +00:00
|
|
|
let selectboxes = [];
|
|
|
|
let userList = [];
|
|
|
|
let lastId = "";
|
|
|
|
let selectedUsers = [];
|
|
|
|
|
2024-03-19 15:08:44 +00:00
|
|
|
function generateFollowersMap() {
|
2024-03-20 01:31:57 +00:00
|
|
|
const checks = Array.from(el_id_listfollowers.querySelectorAll(".follower_checkbox"));
|
2024-03-19 15:08:44 +00:00
|
|
|
let codeMap = {};
|
|
|
|
checks.forEach((checkbox) => {
|
2024-03-20 01:31:57 +00:00
|
|
|
const handle = checkbox.parentElement.parentElement.querySelector(".follower_checkname");
|
2024-03-19 15:08:44 +00:00
|
|
|
codeMap[handle.innerHTML] = checkbox.checked;
|
|
|
|
});
|
2024-03-20 01:28:32 +00:00
|
|
|
return codeMap;
|
2024-03-19 15:08:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function readFollowersMap(m) {
|
|
|
|
if (m == null) return;
|
2024-03-20 01:31:57 +00:00
|
|
|
const handles = Array.from(el_id_listfollowers.querySelectorAll(".follower_checkname"));
|
2024-03-19 15:08:44 +00:00
|
|
|
handles.forEach((handle) => {
|
2024-03-20 01:38:17 +00:00
|
|
|
const checkbox = handle.parentElement.querySelector(".follower_checkbox");
|
2024-03-20 02:59:08 +00:00
|
|
|
checkbox.checked = m[handle.innerHTML] || true;
|
2024-03-19 15:08:44 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-03-19 00:02:11 +00:00
|
|
|
function renderNameHTML(name, user) {
|
2024-03-19 15:08:44 +00:00
|
|
|
return `<span>${escapeHtml(name).replace(/:([a-z0-9_-]+?):/gim, (m, p1) => {
|
2024-03-19 00:02:11 +00:00
|
|
|
const emoji = user.emojis.find(x => x.shortcode == p1);
|
|
|
|
if (emoji == null) return null;
|
|
|
|
return `<img src="${emoji.url}" width="16" height="16" title=":${emoji.shortcode}:" />`;
|
2024-03-19 15:08:44 +00:00
|
|
|
})}</span>`;
|
2024-03-19 00:02:11 +00:00
|
|
|
}
|
|
|
|
|
2024-03-19 17:30:37 +00:00
|
|
|
function startFollowers(reload = true) {
|
2024-03-19 15:08:44 +00:00
|
|
|
goToState("followers");
|
2024-03-19 17:30:37 +00:00
|
|
|
if (reload) {
|
2024-03-19 15:08:44 +00:00
|
|
|
selectboxes = [];
|
|
|
|
userList = [];
|
|
|
|
lastId = "";
|
|
|
|
selectedUsers = [];
|
|
|
|
el_id_listfollowers.innerHTML = "";
|
|
|
|
}
|
2024-03-19 17:30:37 +00:00
|
|
|
getFollowers(!reload);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getFollowers(dontLoadNew = false) {
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_submitfollowers.disabled = true;
|
|
|
|
el_id_morefollowers.disabled = true;
|
|
|
|
let res;
|
|
|
|
let out;
|
|
|
|
if (!dontLoadNew) {
|
|
|
|
el_id_loadingfollowers.innerHTML = `Retrieving followers... Please wait.`;
|
2024-03-19 01:02:49 +00:00
|
|
|
res = await fetch(`https://${game.INSTANCE}/api/v1/accounts/${game.USER_ID}/followers${lastId.length > 0 ? `?max_id=${lastId}` : ""}`);
|
2024-03-19 00:02:11 +00:00
|
|
|
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;
|
2024-03-19 17:30:37 +00:00
|
|
|
out.forEach((cuser) => {
|
|
|
|
const element = document.createElement("tr");
|
|
|
|
element.innerHTML = `<td><input type="checkbox" class="follower_checkbox" checked onchange="checkSelectedAmtFollowers()" /></td>
|
|
|
|
<td><img src="${cuser.avatar}" width="32" height="32" /></td>
|
|
|
|
<td class="follower_namelabel">
|
|
|
|
<a href="${cuser.url}" target="_blank">
|
|
|
|
${renderNameHTML(cuser.display_name, cuser)}
|
|
|
|
</a>
|
|
|
|
</td>
|
|
|
|
<td class="follower_namelabel follower_checkname">@${cuser.fqn}</td>`;
|
|
|
|
el_id_listfollowers.appendChild(element);
|
|
|
|
});
|
2024-03-19 00:02:11 +00:00
|
|
|
userList.push(...out.map(user => ({
|
2024-03-19 01:02:49 +00:00
|
|
|
fqn: user.fqn || user.acct,
|
2024-03-19 00:02:11 +00:00
|
|
|
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,
|
2024-03-19 15:08:44 +00:00
|
|
|
url: user.url
|
2024-03-19 00:02:11 +00:00
|
|
|
})));
|
|
|
|
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();
|
|
|
|
})
|
|
|
|
|
2024-03-19 15:08:44 +00:00
|
|
|
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"))));
|
|
|
|
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_morefollowers.addEventListener("click", () => getFollowers());
|
|
|
|
|
|
|
|
el_id_submitfollowers.addEventListener("click", () => {
|
2024-03-19 15:08:44 +00:00
|
|
|
selectedUsers = [];
|
2024-03-19 00:02:11 +00:00
|
|
|
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");
|
2024-03-19 15:08:44 +00:00
|
|
|
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"));
|
2024-03-20 02:55:49 +00:00
|
|
|
let codeMap = {};
|
2024-03-19 15:08:44 +00:00
|
|
|
checks.forEach((checkbox) => {
|
|
|
|
const handle = checkbox.parentElement.parentElement.querySelector(".following_checkname");
|
2024-03-20 02:55:49 +00:00
|
|
|
codeMap[handle.innerHTML] = checkbox.checked;
|
2024-03-19 15:08:44 +00:00
|
|
|
});
|
2024-03-20 01:28:32 +00:00
|
|
|
return codeMap;
|
2024-03-19 15:08:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function readFollowingMap(m) {
|
|
|
|
if (m == null) return;
|
|
|
|
const handles = Array.from(el_id_listfollowing.querySelectorAll(".following_checkname"));
|
|
|
|
handles.forEach((handle) => {
|
2024-03-20 01:38:17 +00:00
|
|
|
const checkbox = handle.parentElement.querySelector(".following_checkbox");
|
2024-03-20 02:59:08 +00:00
|
|
|
checkbox.checked = m[handle.innerHTML] || true;
|
2024-03-19 15:08:44 +00:00
|
|
|
});
|
|
|
|
}
|
2024-03-19 00:02:11 +00:00
|
|
|
|
2024-03-19 17:30:37 +00:00
|
|
|
function startFollowing(reload = true) {
|
2024-03-19 15:08:44 +00:00
|
|
|
goToState("following");
|
2024-03-19 17:30:37 +00:00
|
|
|
if (reload) {
|
2024-03-19 15:08:44 +00:00
|
|
|
selectboxes = [];
|
|
|
|
userList = [];
|
|
|
|
lastId = "";
|
|
|
|
selectedUsers = [];
|
2024-03-19 17:30:37 +00:00
|
|
|
el_id_listfollowing.innerHTML = "";
|
2024-03-19 15:08:44 +00:00
|
|
|
}
|
2024-03-19 17:30:37 +00:00
|
|
|
getFollowing(!reload);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getFollowing(dontLoadNew = false) {
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_submitfollowing.disabled = true;
|
|
|
|
el_id_morefollowing.disabled = true;
|
|
|
|
let res;
|
|
|
|
let out;
|
|
|
|
if (!dontLoadNew) {
|
|
|
|
el_id_loadingfollowing.innerHTML = `Retrieving following... Please wait.`;
|
2024-03-19 15:08:44 +00:00
|
|
|
res = await fetch(`https://${game.INSTANCE}/api/v1/accounts/${game.USER_ID}/following${lastId.length > 0 ? `?max_id=${lastId}` : ""}`);
|
2024-03-19 00:02:11 +00:00
|
|
|
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;
|
2024-03-19 17:30:37 +00:00
|
|
|
out.forEach((cuser) => {
|
|
|
|
const element = document.createElement("tr");
|
|
|
|
element.innerHTML = `<td><input type="checkbox" class="following_checkbox" checked onchange="checkSelectedAmtFollowing()" /></td>
|
|
|
|
<td><img src="${cuser.avatar}" width="32" height="32" /></td>
|
|
|
|
<td class="following_namelabel">
|
|
|
|
<a href="${cuser.url}" target="_blank">
|
|
|
|
${renderNameHTML(cuser.display_name, cuser)}
|
|
|
|
</a>
|
|
|
|
</td>
|
|
|
|
<td class="following_namelabel following_checkname">@${cuser.fqn}</td>`;
|
|
|
|
el_id_listfollowing.appendChild(element);
|
|
|
|
});
|
2024-03-19 00:02:11 +00:00
|
|
|
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,
|
2024-03-19 15:08:44 +00:00
|
|
|
url: user.url
|
2024-03-19 00:02:11 +00:00
|
|
|
})));
|
|
|
|
lastId = userList.at(-1).id;
|
2024-03-19 15:08:44 +00:00
|
|
|
selectboxes = Array.from(el_id_listfollowing.querySelectorAll(".following_checkbox"));
|
2024-03-19 00:02:11 +00:00
|
|
|
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();
|
|
|
|
})
|
|
|
|
|
2024-03-19 15:08:44 +00:00
|
|
|
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"))));
|
|
|
|
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_morefollowing.addEventListener("click", () => getFollowing());
|
|
|
|
|
|
|
|
el_id_submitfollowing.addEventListener("click", () => {
|
2024-03-19 15:08:44 +00:00
|
|
|
selectedUsers = [];
|
2024-03-19 00:02:11 +00:00
|
|
|
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`;
|
|
|
|
}
|
|
|
|
|
2024-03-19 17:30:37 +00:00
|
|
|
// 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 = `<td><input type="checkbox" class="manual_checkbox" checked onchange="checkSelectedAmtManual()" /></td>
|
|
|
|
<td><img src="${out.avatar}" width="32" height="32" /></td>
|
|
|
|
<td class="manual_namelabel">
|
|
|
|
<a href="${out.url}" target="_blank">
|
|
|
|
${renderNameHTML(out.display_name, out)}
|
|
|
|
</a>
|
|
|
|
</td>
|
|
|
|
<td class="manual_namelabel manual_checkname">@${out.fqn}</td>`;
|
|
|
|
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`;
|
|
|
|
}
|
|
|
|
|
2024-03-19 00:02:11 +00:00
|
|
|
// 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");
|
2024-03-19 15:08:44 +00:00
|
|
|
// const el_id_gameUserOneNote = document.querySelector("#gameUserOneNote");
|
|
|
|
// const el_id_gameUserOneFields = document.querySelector("#gameUserOneFields");
|
2024-03-19 00:02:11 +00:00
|
|
|
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");
|
2024-03-19 15:08:44 +00:00
|
|
|
// const el_id_gameUserTwoNote = document.querySelector("#gameUserTwoNote");
|
|
|
|
// const el_id_gameUserTwoFields = document.querySelector("#gameUserTwoFields");
|
2024-03-19 00:02:11 +00:00
|
|
|
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() {
|
2024-03-19 15:08:44 +00:00
|
|
|
goToState("game");
|
|
|
|
state = [];
|
|
|
|
curDepth = 0;
|
|
|
|
curFight = 0;
|
2024-03-19 00:02:11 +00:00
|
|
|
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;
|
2024-03-19 15:08:44 +00:00
|
|
|
el_id_gameUserOneName.innerHTML = `<a href="${curSubStage[0].url}" target="_blank">${renderNameHTML(escapeHtml(curSubStage[0].display_name), curSubStage[0])}</a>`;
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_gameUserOneId.innerHTML = "@" + curSubStage[0].fqn;
|
2024-03-19 15:08:44 +00:00
|
|
|
// el_id_gameUserOneNote.innerHTML = escapeHtml(curSubStage[0].note);
|
|
|
|
// el_id_gameUserOneFields.innerHTML = curSubStage[0].fields.reduce((pv, fields) => pv + `<tr><td>${escapeHtml(fields.name)}</td><td>${escapeHtml(fields.value)}</td></tr>`, "");
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_gameUserTwoImage.src = curSubStage[1].avatar;
|
2024-03-19 15:08:44 +00:00
|
|
|
el_id_gameUserTwoName.innerHTML = `<a href="${curSubStage[1].url}" target="_blank">${renderNameHTML(escapeHtml(curSubStage[1].display_name), curSubStage[1])}</a>`;
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_gameUserTwoId.innerHTML = "@" + curSubStage[1].fqn;
|
2024-03-19 15:08:44 +00:00
|
|
|
// el_id_gameUserTwoNote.innerHTML = escapeHtml(curSubStage[1].note);
|
|
|
|
// el_id_gameUserTwoFields.innerHTML = curSubStage[1].fields.reduce((pv, fields) => pv + `<tr><td>${escapeHtml(fields.name)}</td><td>${escapeHtml(fields.value)}</td></tr>`, "");
|
2024-03-19 00:02:11 +00:00
|
|
|
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");
|
2024-03-19 15:08:44 +00:00
|
|
|
// const el_id_winnerUserNote = document.querySelector("#winnerUserNote");
|
|
|
|
// const el_id_winnerUserFields = document.querySelector("#winnerUserFields");
|
2024-03-19 00:02:11 +00:00
|
|
|
const el_id_winnermessage = document.querySelector("#winnermessage");
|
|
|
|
const el_id_winnerusers = document.querySelector("#winnerusers");
|
|
|
|
const el_id_winnerPlayAgain = document.querySelector("#winnerPlayAgain");
|
|
|
|
|
|
|
|
function endGame() {
|
2024-03-19 15:08:44 +00:00
|
|
|
goToState("winner");
|
2024-03-19 00:02:11 +00:00
|
|
|
const winningPlayer = state[curDepth][curFight][0];
|
|
|
|
el_id_winnerUserImage.src = winningPlayer.avatar;
|
2024-03-19 15:08:44 +00:00
|
|
|
el_id_winnerUserName.innerHTML = `<a href="${winningPlayer.url}" target="_blank">${renderNameHTML(escapeHtml(winningPlayer.display_name), winningPlayer)}</a>`;
|
2024-03-19 00:02:11 +00:00
|
|
|
el_id_winnerUserId.innerHTML = "@" + winningPlayer.fqn;
|
2024-03-19 15:08:44 +00:00
|
|
|
// el_id_winnerUserNote.innerHTML = escapeHtml(winningPlayer.note);
|
|
|
|
// el_id_winnerUserFields.innerHTML = winningPlayer.fields.reduce((pv, fields) => pv + `<tr><td>${escapeHtml(fields.name)}</td><td>${escapeHtml(fields.value)}</td></tr>`, "");
|
2024-03-19 00:02:11 +00:00
|
|
|
|
|
|
|
el_id_winnermessage.innerHTML = `Congratulations, ${renderNameHTML(escapeHtml(winningPlayer.display_name), winningPlayer)}! You won the bracket!`;
|
2024-03-20 02:49:13 +00:00
|
|
|
el_id_winnerusers.innerHTML = state.reduce((pv, cs) => {
|
2024-03-19 00:02:11 +00:00
|
|
|
return pv + `<div class="flexUser">${cs.reduce((pvus, cus) => {
|
2024-03-20 02:49:13 +00:00
|
|
|
console.log(cus);
|
|
|
|
return pvus + `<div class="flexUserGroup"><div class="flexUserUser">
|
|
|
|
<img src="${cus[0].avatar}" width="64" height="64" />
|
|
|
|
<h3><a href="${cus[0].url}" target="_blank">${renderNameHTML(escapeHtml(cus[0].display_name), cus[0])}</a></h3>
|
|
|
|
<p>@${cus[0].fqn}</p>
|
|
|
|
</div>${cus[1] ? `<div class="flexUserUser">
|
|
|
|
<img src="${cus[1].avatar}" width="64" height="64" />
|
|
|
|
<h3><a href="${cus[1].url}" target="_blank">${renderNameHTML(escapeHtml(cus[1].display_name), cus[1])}</a></h3>
|
|
|
|
<p>@${cus[1].fqn}</p>
|
|
|
|
</div>` : ""}</div>`
|
2024-03-19 00:02:11 +00:00
|
|
|
}, "")}</div>`
|
2024-03-20 02:49:13 +00:00
|
|
|
}, "");
|
2024-03-19 00:02:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
el_id_winnerPlayAgain.addEventListener("click", (x) => {
|
|
|
|
state = [];
|
|
|
|
selectedUsers = [];
|
|
|
|
curDepth = 0;
|
|
|
|
curFight = 0;
|
2024-03-19 17:30:37 +00:00
|
|
|
switch (gamemodeFollowers) {
|
|
|
|
case "followers":
|
|
|
|
startFollowers(false);
|
|
|
|
break;
|
|
|
|
case "following":
|
|
|
|
startFollowing(false);
|
|
|
|
break;
|
|
|
|
case "manual":
|
|
|
|
startManual(false);
|
|
|
|
break;
|
|
|
|
}
|
2024-03-19 04:17:45 +00:00
|
|
|
})
|
|
|
|
|
2024-03-19 15:08:44 +00:00
|
|
|
// Game state
|
|
|
|
|
|
|
|
const gameStates = new Map([
|
|
|
|
["whoami", {
|
|
|
|
state: el_id_whoami
|
|
|
|
}],
|
|
|
|
["followers", {
|
|
|
|
state: el_id_followers
|
|
|
|
}],
|
|
|
|
["following", {
|
|
|
|
state: el_id_following
|
|
|
|
}],
|
2024-03-19 17:30:37 +00:00
|
|
|
["manual", {
|
|
|
|
state: el_id_manual
|
|
|
|
}],
|
2024-03-19 15:08:44 +00:00
|
|
|
["game", {
|
|
|
|
state: el_id_game,
|
|
|
|
links: {
|
2024-03-19 17:30:37 +00:00
|
|
|
"winner": () => gamemodeFollowers
|
2024-03-19 15:08:44 +00:00
|
|
|
}
|
|
|
|
}],
|
|
|
|
["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;
|
2024-03-19 04:17:45 +00:00
|
|
|
}
|
|
|
|
|
2024-03-19 15:08:44 +00:00
|
|
|
goToState("whoami");
|
|
|
|
|
|
|
|
addEventListener("popstate", () => goToState(window.location.hash.slice(1)));
|