random bun scripts that dont fit anywhere else
at main 9.0 kB view raw
1// ==UserScript== 2// @name Hack Club Summer Votes Helper 3// @namespace http://tampermonkey.net/ 4// @version 0.2 5// @description Enhance the voting experience on Hack Club Summer votes page 6// @author You 7// @match https://summer.hackclub.com/votes/new 8// @match https://summer.hackclub.com/votes/* 9// @grant none 10// ==/UserScript== 11 12(() => { 13 console.log("Hack Club Summer Votes Helper loaded"); 14 15 function addHackClubSummerVotesHelperButton() { 16 // Prevent adding multiple buttons 17 if (document.getElementById("hackclub-summer-votes-helper-btn")) { 18 console.log("Button already exists, skipping"); 19 return; 20 } 21 22 // Find the <p class="text-center"> element 23 const p = document.querySelector("p.text-center"); 24 if (!p) { 25 console.log("Target element not found yet"); 26 return; 27 } 28 29 console.log("Adding helper button"); 30 31 // Create a new button 32 const openButton = document.createElement("button"); 33 openButton.textContent = "Open Project Links"; 34 openButton.style.margin = "10px"; 35 openButton.style.display = "block"; 36 openButton.style.marginLeft = "auto"; 37 openButton.style.marginRight = "auto"; 38 openButton.className = "som-button-primary"; 39 openButton.id = "hackclub-summer-votes-helper-btn"; 40 41 // Add click event to open the URLs 42 function openProjectLinks() { 43 console.log("Helper button clicked"); 44 45 // Find all buttons with a div > span whose text is "Demo" or "Repository" 46 const allButtons = Array.from( 47 document.getElementsByClassName("som-button-primary"), 48 ); 49 const filteredButtons = allButtons.filter((btn) => { 50 const spans = btn.querySelectorAll("div > span"); 51 return Array.from(spans).some((span) => { 52 const text = span.textContent.trim(); 53 return text === "Demo" || text === "Repository"; 54 }); 55 }); 56 57 console.log(`Found ${filteredButtons.length} project buttons`); 58 59 filteredButtons.forEach((btn) => { 60 const url = btn.href || btn.getAttribute("data-href"); 61 if (url) { 62 console.log(`Opening: ${url}`); 63 window.open(url, "_blank"); 64 } 65 }); 66 67 // Set the hidden inputs to true 68 const inputIds = [ 69 "vote_project_1_demo_opened", 70 "vote_project_1_repo_opened", 71 "vote_project_2_demo_opened", 72 "vote_project_2_repo_opened", 73 ]; 74 75 inputIds.forEach((id) => { 76 const input = document.getElementById(id); 77 if (input) { 78 input.value = "true"; 79 console.log(`Set ${id} to true`); 80 } 81 }); 82 } 83 84 openButton.addEventListener("click", openProjectLinks); 85 86 p.appendChild(openButton); 87 console.log("Button added successfully"); 88 } 89 90 function runHelperOnPageLoad() { 91 // Only run on the correct page 92 if ( 93 window.location.pathname === "/votes/new" || 94 window.location.pathname.startsWith("/votes/") 95 ) { 96 console.log("Running helper on correct page"); 97 addHackClubSummerVotesHelperButton(); 98 } 99 } 100 101 // Initial run 102 runHelperOnPageLoad(); 103 104 // Method 1: Intercept fetch/XMLHttpRequest to detect page changes 105 const originalFetch = window.fetch; 106 window.fetch = function (...args) { 107 return originalFetch.apply(this, args).then((response) => { 108 if (response.url.includes("/votes/new")) { 109 console.log("Detected fetch to votes page"); 110 setTimeout(runHelperOnPageLoad, 100); 111 } 112 return response; 113 }); 114 }; 115 116 const originalXHROpen = XMLHttpRequest.prototype.open; 117 XMLHttpRequest.prototype.open = function (method, url, ...rest) { 118 this.addEventListener("load", () => { 119 if (url.includes("/votes/new")) { 120 console.log("Detected XHR to votes page"); 121 setTimeout(runHelperOnPageLoad, 100); 122 } 123 }); 124 return originalXHROpen.call(this, method, url, ...rest); 125 }; 126 127 // Method 2: Enhanced MutationObserver 128 let observerTimeout; 129 const observer = new MutationObserver((_mutations) => { 130 // Debounce to avoid excessive calls 131 clearTimeout(observerTimeout); 132 observerTimeout = setTimeout(() => { 133 console.log("DOM mutation detected"); 134 runHelperOnPageLoad(); 135 }, 50); 136 }); 137 138 // Observe the entire document for changes 139 observer.observe(document.documentElement, { 140 childList: true, 141 subtree: true, 142 attributes: false, 143 }); 144 145 // Method 3: Polling fallback (less elegant but very reliable) 146 setInterval(() => { 147 if ( 148 window.location.pathname === "/votes/new" || 149 window.location.pathname.startsWith("/votes/") 150 ) { 151 if (!document.getElementById("hackclub-summer-votes-helper-btn")) { 152 console.log("Button missing, re-adding via polling"); 153 addHackClubSummerVotesHelperButton(); 154 } 155 } 156 }, 2000); 157 158 // Method 4: Listen for history changes 159 const originalPushState = history.pushState; 160 const originalReplaceState = history.replaceState; 161 162 history.pushState = function (...args) { 163 originalPushState.apply(this, args); 164 setTimeout(runHelperOnPageLoad, 100); 165 }; 166 167 history.replaceState = function (...args) { 168 originalReplaceState.apply(this, args); 169 setTimeout(runHelperOnPageLoad, 100); 170 }; 171 172 window.addEventListener("popstate", () => { 173 setTimeout(runHelperOnPageLoad, 100); 174 }); 175 176 // Method 5: Listen for focus events (when user returns to tab) 177 window.addEventListener("focus", () => { 178 setTimeout(runHelperOnPageLoad, 100); 179 }); 180 181 // Add listener for Shift + S shortcut 182 window.addEventListener("keydown", (e) => { 183 // Ignore if input/textarea/select is focused 184 const tag = document.activeElement.tagName; 185 if ( 186 tag === "INPUT" || 187 tag === "TEXTAREA" || 188 tag === "SELECT" || 189 document.activeElement.isContentEditable 190 ) { 191 return; 192 } 193 if (e.shiftKey && (e.key === "s" || e.key === "S")) { 194 // Only run on the correct page 195 if ( 196 window.location.pathname === "/votes/new" || 197 window.location.pathname.startsWith("/votes/") 198 ) { 199 const btn = document.getElementById("hackclub-summer-votes-helper-btn"); 200 if (btn) { 201 btn.click(); 202 } else { 203 // If button not present, run the logic directly 204 // (duplicate logic from openButton click) 205 // Find all buttons with a div > span whose text is "Demo" or "Repository" 206 const allButtons = Array.from( 207 document.getElementsByClassName("som-button-primary"), 208 ); 209 const filteredButtons = allButtons.filter((btn) => { 210 const spans = btn.querySelectorAll("div > span"); 211 return Array.from(spans).some((span) => { 212 const text = span.textContent.trim(); 213 return text === "Demo" || text === "Repository"; 214 }); 215 }); 216 217 filteredButtons.forEach((btn) => { 218 const url = btn.href || btn.getAttribute("data-href"); 219 if (url) { 220 window.open(url, "_blank"); 221 } 222 }); 223 224 // Set the hidden inputs to true 225 const inputIds = [ 226 "vote_project_1_demo_opened", 227 "vote_project_1_repo_opened", 228 "vote_project_2_demo_opened", 229 "vote_project_2_repo_opened", 230 ]; 231 232 inputIds.forEach((id) => { 233 const input = document.getElementById(id); 234 if (input) { 235 input.value = "true"; 236 } 237 }); 238 } 239 // Prevent default browser behavior 240 e.preventDefault(); 241 } 242 } 243 }); 244 245 // Add listener for Ctrl+Enter to submit vote, even in a textbox 246 window.addEventListener("keydown", (e) => { 247 if (e.ctrlKey && (e.key === "Enter" || e.keyCode === 13)) { 248 // Only run on the correct page 249 if ( 250 window.location.pathname === "/votes/new" || 251 window.location.pathname.startsWith("/votes/") 252 ) { 253 // Find the submit vote button 254 // <button name="button" type="submit" class="som-button-primary " data-form-target="submitButton"> 255 // <div class="flex items-center justify-center gap-2"> 256 // <span class="flex items-center gap-1">Submit Vote</span> 257 // </div> 258 // </button> 259 const submitButtons = Array.from( 260 document.querySelectorAll( 261 'button.som-button-primary[data-form-target="submitButton"]', 262 ), 263 ); 264 let found = false; 265 for (const btn of submitButtons) { 266 // Check if the button contains a span with text "Submit Vote" 267 const span = btn.querySelector("span"); 268 if (span && span.textContent.trim() === "Submit Vote") { 269 btn.click(); 270 found = true; 271 break; 272 } 273 } 274 if (found) { 275 e.preventDefault(); 276 } 277 } 278 } 279 }); 280 281 console.log("All event listeners and observers set up"); 282})();