diff --git a/tampermonkey.js b/tampermonkey.js
new file mode 100644
index 0000000..02b0514
--- /dev/null
+++ b/tampermonkey.js
@@ -0,0 +1,332 @@
+// ==UserScript==
+// @name Fet Group Blocker
+// @namespace http://tampermonkey.net/
+// @version 0.1
+// @description Block all users in a given FetLife Group
+// @author ⬡-Drone 4661
+// @match https://fetlife.com/*
+// @icon https://www.google.com/s2/favicons?sz=64&domain=fetlife.com
+// @grant none
+// ==/UserScript==
+
+
+const expiration = 6000000;
+const appendButton = () => {
+ let joinButton = document.getElementsByClassName("flex-none pl-3.5 pt-2 xs:pl-8 lg:pt-0");
+ if (joinButton.length < 1) {
+ return;
+ }
+ let parentFlex = joinButton[0].parentElement;
+ let buttonLabel = "🛑 Block Group Members";
+ if (localStorage.getItem("FetlifeBlocker") !== null) {
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ if (blocker.group.toString() === window.location.href.split("/")[4]) {
+ if (blocker.activation + expiration /*10 minutes*/ < Date.now() || blocker.status === "expired") {
+ console.log("Expired but from the button adder");
+ buttonLabel = "❌ Auto-Block Expired";
+ } else {
+ switch (blocker.status) {
+ case "nav":
+ case "scrape":
+ buttonLabel = "🔄️ Scanning...";
+ break;
+ case "block":
+ buttonLabel = "🔄️ Blocking...";
+ break;
+ case "complete":
+ buttonLabel = "✅ Blocking Complete";
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ }
+ parentFlex.innerHTML = parentFlex.innerHTML + `
+
';
+ let blockMemberButton = document.getElementById("blockMemberButton");
+ blockMemberButton.onclick = () => {
+ // Scrape group members
+ // Block each member
+ if (localStorage.getItem("FetlifeBlocker") === null) {
+ // First click
+ localStorage.setItem("FetlifeBlocker", JSON.stringify({
+ "origin": window.location.href,
+ "members": [],
+ "group": parseInt(window.location.href.split("/")[4]),
+ "activation": Date.now(),
+ "status": "nav"
+ }));
+ window.location.href = "https://fetlife.com/groups/" + parseInt(window.location.href.split("/")[4]) + "/members?page=1";
+ } else {
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ if (blocker.status == "complete" || blocker.status == "expired") {
+ // First click
+ localStorage.setItem("FetlifeBlocker", JSON.stringify({
+ "origin": window.location.href,
+ "members": [],
+ "group": parseInt(window.location.href.split("/")[4]),
+ "activation": Date.now(),
+ "status": "nav"
+ }));
+ window.location.href = "https://fetlife.com/groups/" + parseInt(window.location.href.split("/")[4]) + "/members?page=1";
+ }
+ }
+ };
+ return;
+};
+
+const navigateToNextPage = () => {
+ // get next page num from processed nav
+ // if already last page, update localStorage and return to origin
+ // localstorage (FetlifeBlocker -> null, FetLifeBlockedUsers -> +=members)
+ let nav = document.getElementsByClassName("pagination mt-6 text-center");
+ if (nav.length > 0) {
+ if (nav[0].children[nav[0].children.length - 1].toString().includes("members")){
+ // not last page yet
+ window.location.href = nav[0].children[nav[0].children.length - 1].toString();
+ return;
+ }
+ }
+ // last page
+ // All members have been scraped
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ blocker.status = "block";
+ localStorage.setItem("FetlifeBlocker", JSON.stringify(blocker));
+ window.location.href = blocker.origin;
+ return;
+};
+
+const scrapeMembers = () => {
+ if ( document.body.classList.toString().includes("page-loading") ) {
+ // still loading
+ // Retry after 1.5 seconds
+ setTimeout(scrapeMembers, 1500);
+ return;
+ }
+ // get all members
+ let users = [];
+ // Foe each column
+ document.getElementsByClassName("w-full px-1 md:w-1/2").forEach(i => {
+ // For each member element
+ for (let y = 0; y < i.children.length; y++){
+ let userElement = i.children[y].children[0].children[0].children[1].children[0].children[0];
+ let UserID = userElement.href.split("/")[4];
+ let UserName = userElement.innerText;
+ users.push({
+ "id": UserID,
+ "name": UserName
+ });
+ }
+ });
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ users.forEach(i => {
+ if (!blocker.members.some(e => e.id === i.id)) {
+ blocker.members.push(i);
+ }
+ });
+ localStorage.setItem("FetlifeBlocker", JSON.stringify(blocker));
+
+ navigateToNextPage();
+};
+
+const nextUser = () => {
+ let userBlock = JSON.parse(localStorage.getItem("FetlifeUserBlock"));
+ if (userBlock === null) {
+ window.location.href = "https://fetlife.com/groups";
+ return;
+ }
+ // Navigate to next user
+ if (userBlock.users.length < 1) {
+ // No users left
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ blocker.status = "complete";
+ localStorage.setItem("FetlifeBlocker", JSON.stringify(blocker));
+ localStorage.removeItem("FetlifeUserBlock");
+ window.location.href = userBlock.origin;
+ } else {
+ window.location.href = "https://fetlife.com/users/" + userBlock.users[0].id;
+ }
+ return;
+};
+
+(function() {
+ 'use strict';
+ switch (window.location.pathname.split("/")[1]) {
+ case "groups":
+ if (/^[0-9]+$/.test(window.location.pathname.split("/")[2].toLowerCase())){
+ appendButton();
+ if (localStorage.getItem("FetlifeBlocker") !== null) {
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ // Block run expired.. reset to null
+ if (blocker.activation + expiration /*10 minutes*/ < Date.now()) {
+ console.log("Expired");
+ blocker.status = "expired";
+ blocker.members = [];
+ localStorage.setItem("FetlifeBlocker", JSON.stringify(blocker));
+ // localStorage.removeItem("FetlifeBlocker");
+ return;
+ }
+ switch (blocker.status) {
+ case "nav":
+ if (!window.location.href.toLowerCase().startsWith("https://fetlife.com/groups/" + blocker.group + "/members")) {
+ // not on a member page, navigate to next page
+ window.location.href = "https://fetlife.com/groups/" + blocker.group + "/members?page=1";
+ return;
+ }else {
+ // on a member page now
+ blocker.status = "scrape";
+ localStorage.setItem("FetlifeBlocker", JSON.stringify(blocker));
+ window.location.href = "https://fetlife.com/groups/" + blocker.group + "/members?page=1";
+ return;
+ }
+ break;
+ case "scrape":
+ scrapeMembers();
+ break;
+ case "block":
+ // Prepare data for user page cycling
+ localStorage.setItem("FetlifeUserBlock", JSON.stringify({
+ "origin": blocker.origin,
+ "users": blocker.members,
+ "activation": Date.now(),
+ }));
+ // Navigate to first user
+ window.location.href = "https://fetlife.com/users/" + blocker.members[0].id;
+ break;
+ case "complete":
+ console.log("TODO: Announce errors if any, otherwise complete!");
+ let errors = localStorage.getItem("FetlifeError")?JSON.parse(localStorage.getItem("FetlifeError")):[];
+ if (errors.length > 0) {
+ console.log("Errors: ", errors.length);
+ } else {
+ console.log("No errors");
+ }
+ localStorage.removeItem("FetlifeError");
+ break;
+ case "expired":
+ console.log("Expired, but from status processing");
+ localStorage.removeItem("FetlifeError");
+ break;
+ default:
+ // TODO?
+ break;
+ }
+ }
+ }
+ break;
+ case "users":
+ // If on a user page
+ if (/^[0-9]+$/.test(window.location.pathname.split("/")[2].toLowerCase())){
+ console.log("User page");
+ // check localstorage
+ if (localStorage.getItem("FetlifeUserBlock") !== null) {
+ let userBlock = JSON.parse(localStorage.getItem("FetlifeUserBlock"));
+ console.log("UserBlock: ", window.location.pathname.split("/")[2]);
+ // check within 10 minutes
+ if (userBlock.activation + expiration /*10 minutes*/ < Date.now()) {
+ localStorage.removeItem("FetlifeUserBlock");
+ console.log("Expired");
+ return;
+ }
+ // if user in list, block and nav to next user
+ if (userBlock.users.some(e => e.id.toString() === window.location.pathname.split("/")[2])) {
+ // If user already blocked, remove from list and skip
+ if (document.getElementsByTagName("body")[0].innerText.toLowerCase().includes("you've blocked")){
+ console.log(`User ${window.location.pathname.split("/")[2]} already blocked`);
+ // Remove user listing from localstorage
+ userBlock.users = userBlock.users.filter(e => e.id.toString() !== window.location.pathname.split("/")[2]);
+ localStorage.setItem("FetlifeUserBlock", JSON.stringify(userBlock));
+ // Navigate to next user
+ nextUser();
+ return;
+ } else if (document.getElementsByTagName("body")[0].innerText.toLowerCase().includes("isn't available")) {
+ console.log(`User ${window.location.pathname.split("/")[2]} not available`);
+ // Remove user listing from localstorage
+ userBlock.users = userBlock.users.filter(e => e.id.toString() !== window.location.pathname.split("/")[2]);
+ localStorage.setItem("FetlifeUserBlock", JSON.stringify(userBlock));
+ let errors = localStorage.getItem("FetlifeError")?JSON.parse(localStorage.getItem("FetlifeError")):[];
+ errors.push({
+ "user": window.location.pathname.split("/")[2],
+ "error": "User not available"
+ });
+ localStorage.setItem("FetlifeError", JSON.stringify(errors));
+ // Navigate to next user
+ nextUser();
+ return;
+ } else {
+ // Block user
+ console.log("TODO: Block user");
+ let blockButton = document.querySelectorAll('[title="Block"]');
+ if (blockButton.length > 0) {
+ console.log("Clicking block");
+ blockButton[0].click();
+ setTimeout( () => {
+ // If can't block
+ let confirmButton = document.getElementsByClassName("relative no-underline items-center rounded-sm select-none border link red-100 border-red-600 hover-red-100 bg-red-600 hover:bg-red-700 transition fill-red-100 leading-tighter text-md py-2 px-2 xs:px-3.5 font-normal text-center justify-center flex w-full");
+ if (confirmButton.length > 0) {
+ userBlock.users = userBlock.users.filter(e => e.id.toString() !== window.location.pathname.split("/")[2]);
+ localStorage.setItem("FetlifeUserBlock", JSON.stringify(userBlock));
+ if (confirmButton[0].innerText.toLowerCase().includes("gotcha")) {
+ // Cannot block user
+ console.log("Cannot block user" + window.location.pathname.split("/")[2]);
+ let FetLifeError = localStorage.getItem("FetlifeError")?JSON.parse(localStorage.getItem("FetlifeError")):[];
+ FetLifeError.push({
+ "user": window.location.pathname.split("/")[2],
+ "error": "Cannot block user"
+ });
+ // remove user from list
+ userBlock.users = userBlock.users.filter(e => e.id.toString() !== window.location.pathname.split("/")[2]);
+ localStorage.setItem("FetlifeUserBlock", JSON.stringify(userBlock));
+ localStorage.setItem("FetlifeError", JSON.stringify(FetLifeError));
+ nextUser();
+ } else {
+ console.log("User " + window.location.pathname.split("/")[2] + " blocked");
+ confirmButton[0].click();
+ setTimeout( () => {
+ location.reload();
+ }, 5000);
+ }
+ }
+ }, 500);
+ } else {
+ console.log("No block button");
+ }
+ }
+
+ }else {
+ // Navigate to fist user in list
+ if (userBlock.users.length < 1) {
+ // No users left
+ console.log("Missing current page user: No users left");
+ localStorage.removeItem("FetlifeUserBlock");
+ let blocker = JSON.parse(localStorage.getItem("FetlifeBlocker"));
+ blocker.status = "complete";
+ localStorage.setItem("FetlifeBlocker", JSON.stringify(blocker));
+ window.location.href = userBlock.origin;
+ } else {
+ console.log("Missing current page user: Navigating to next user");
+ window.location.href = "https://fetlife.com/users/" + userBlock.users[0].id;
+ }
+ return;
+ }
+ return;
+ } else {
+ console.log("No users to block");
+ }
+ } else {
+ console.log("Not a user page");
+ }
+ break;
+ default:
+ console.log("Not a group or user page");
+ break;
+ }
+})();