NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Winner Selection Script // @description Automates the process of picking winners from the first post's like list in forum giveaways. Ensures a fair and transparent winner selection. // @namespace https://github.com/Zw3tty/WinnerSelectionScript // @version 1.7.1 // @author NotZw3tty // @match https://gamesense.pub/forums/viewtopic.php?id=* // @grant none // @updateURL https://github.com/Zw3tty/WinnerSelectionScript/raw/main/GiveawayWinnerPicker.user.js // @downloadURL https://github.com/Zw3tty/WinnerSelectionScript/raw/main/GiveawayWinnerPicker.user.js // @supportURL https://github.com/Zw3tty/WinnerSelectionScript/issues // @license MIT // ==/UserScript== (function() { 'use strict'; function getUserData(likelistId) { const users = []; document.querySelectorAll(`#${likelistId} li a`).forEach((element) => { const username = element.textContent.trim(); const uid = element.href.match(/id=(\d+)/)[1]; if (!element.classList.contains('usergroup-6')) { // exclude banned users users.push({ username, uid }); } }); return users; } function pickWinners(userData, numberOfWinners) { if (numberOfWinners < 1 || numberOfWinners > userData.length) { alert("Invalid number of winners. Please choose a number between 1 and " + userData.length); return []; } const winners = []; while (winners.length < numberOfWinners) { if (userData.length === 0) break; const randomIndex = Math.floor(Math.random() * userData.length); winners.push(userData.splice(randomIndex, 1)[0]); // Remove the selected winner } if (winners.length === 0) { console.error("No winners selected."); return []; } return winners; } function generateWinnersOutput(winners) { const formatChoice = prompt( "Choose the output format:\n" + "1: @Username (ID: XXXXX)\n" + "2: Username (ID: XXXXX)\n" + "3: @Username\n" + "4: Username\n" + "5: @Username (ID: XXXXX), each on new line\n" + "6: Username (ID: XXXXX), each on new line\n" + "7: @Username, each on new line\n" + "8: Username, each on new line\n" + "Enter a number from 1 to 8:" ); let formatFunction; switch (formatChoice) { case '1': formatFunction = user => `@${user.username} (ID: ${user.uid})`; break; case '2': formatFunction = user => `${user.username} (ID: ${user.uid})`; break; case '3': formatFunction = user => `@${user.username}`; break; case '4': formatFunction = user => `${user.username}`; break; case '5': formatFunction = user => `@${user.username} (ID: ${user.uid})`; break; case '6': formatFunction = user => `${user.username} (ID: ${user.uid})`; break; case '7': formatFunction = user => `@${user.username}`; break; case '8': formatFunction = user => `${user.username}`; break; default: formatFunction = user => `@${user.username} (ID: ${user.uid})`; } let winnersText = "Winners:"; if (['5', '6', '7', '8'].includes(formatChoice)) { winnersText += "\n" + winners.map(formatFunction).join('\n'); } else { winnersText += " " + winners.map(formatFunction).join(', '); } return winnersText; } function getUserIdFromHref(href) { const match = href.match(/id=(\d+)/); return match ? match[1] : null; } function addButtonsToFirstPostFoot() { const loggedInUserId = getUserIdFromHref(document.querySelector('#navprofile a').href); const postAuthorId = getUserIdFromHref(document.querySelector('.postleft dt a').href); if (loggedInUserId === postAuthorId) { const firstPostFootRight = document.querySelector('.postfootright > ul'); if (firstPostFootRight) { const pickWinnersLi = document.createElement('li'); pickWinnersLi.className = 'postpickgw'; const pickWinnersLink = document.createElement('a'); pickWinnersLink.textContent = 'Pick Winners'; pickWinnersLink.href = '#'; pickWinnersLink.style.color = '#60a0dc'; pickWinnersLink.style.fontSize = '11px'; pickWinnersLink.style.cursor = 'pointer'; pickWinnersLi.appendChild(pickWinnersLink); firstPostFootRight.appendChild(pickWinnersLi); let copyWinnersLi; // will be created after winners are picked pickWinnersLink.onclick = function(event) { event.preventDefault(); const likelistId = document.querySelector('ul.likelist').id; const numberOfWinners = prompt("Enter the number of winners: "); if (numberOfWinners) { const userData = getUserData(likelistId); const winners = pickWinners(userData, parseInt(numberOfWinners, 10)); if (winners.length > 0) { const winnersText = generateWinnersOutput(winners); alert(winnersText); if (!copyWinnersLi) { copyWinnersLi = document.createElement('li'); copyWinnersLi.className = 'postcopygw'; const copyWinnersButton = document.createElement('a'); copyWinnersButton.textContent = 'Copy Winners'; copyWinnersButton.href = '#'; copyWinnersButton.style.color = '#60a0dc'; copyWinnersButton.style.fontSize = '11px'; copyWinnersButton.style.cursor = 'pointer'; copyWinnersButton.onclick = function(e) { e.preventDefault(); navigator.clipboard.writeText(winnersText).then(function() { alert('Winners copied to clipboard!'); }, function(err) { console.error('Could not copy text: ', err); }); }; copyWinnersLi.appendChild(copyWinnersButton); firstPostFootRight.appendChild(copyWinnersLi); } } else { alert("No winners were selected."); } } }; } } else { console.log('User is not the author of the post, not adding Giveaway Picker buttons.'); } } addButtonsToFirstPostFoot(); })();