您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
automatically suggest players to your table on BGA.
// ==UserScript== // @name bga-auto-suggest // @namespace https://github.com/nqztv/bga-auto-suggest // @version 0.3.1 // @description automatically suggest players to your table on BGA. // @include *.boardgamearena.com/* // @grant none // ==/UserScript== // // on boardgamearena.com, players will often not join your table unless they are // suggested to that table. bga also limits you to 1 suggestion every 5 seconds. // so manually suggesting players to your table can be a tedious process. // insectman from the perudo community wrote an proof of concept script to // automate this process. @nqztv rewrote his script to work as a user script on // greasemonkey or tampermonkey while taking away dependencies and stuff. // @naXa777 modified this script so it works endlessly until the user interrupts // it by pressing STOP button. // // you can adjust the minimum Elo, add people to the white list, or add people // to a blacklist below if you wish to. // VARIABLES TO SET USER PREFERENCE var minimumElo = 100; var blackList = []; var whiteList = ["nqztv", "insectman", "pnight"]; var autoStartGame = false; // start game when enough players? // INTERNAL VARIABLES var alreadySuggested = []; var suggestPlayers = true; var interrupted = false; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function init() { console.log("Creating auto suggest button."); await sleep(2000); // delay; the script is loaded faster then the BGA UI sometimes var bgaButtonBarNode = document.querySelector(".bgabuttonbar"); if (!bgaButtonBarNode) { console.error("Please reload the page."); return; } var span = document.createElement("span"); span.innerHTML = "Auto Suggest"; var autoSuggestButton = document.createElement("div"); autoSuggestButton.append(span); autoSuggestButton.setAttribute("id", "autosuggest"); autoSuggestButton.className = "bgabutton bgabutton_gray tableaction"; bgaButtonBarNode.appendChild(autoSuggestButton); var span = document.createElement("span"); span.innerHTML = "Stop Auto Suggest"; var stopSuggestButton = document.createElement("div"); stopSuggestButton.append(span); stopSuggestButton.setAttribute("id", "stopsuggest"); stopSuggestButton.setAttribute("style", "display: none;"); stopSuggestButton.className = "bgabutton bgabutton_gray tableaction"; bgaButtonBarNode.appendChild(stopSuggestButton); document.getElementById("autosuggest").addEventListener("click", loop, false); document.getElementById("stopsuggest").addEventListener("click", stopLoop, false); } async function stopLoop() { suggestPlayers = false; interrupted = true; // hide Stop Auto Suggest button, show Auto Suggest button var autoSuggestButton = document.getElementById("autosuggest"); if (autoSuggestButton) autoSuggestButton.setAttribute("style", "display: inline;"); var stopSuggestButton = document.getElementById("stopsuggest"); if (stopSuggestButton) stopSuggestButton.setAttribute("style", "display: none;"); } async function loop() { console.log("Beginning auto suggestions..."); if (autoStartGame) { observeStartButton(); } var availablePlayersNode = document.querySelector("#available_players_for_game"); var availablePlayers; var tableID = window.location.href.split("table=")[1]; var index = 0; var playerAttributes = []; var playerName = ""; /** * Caption: Suggestion sent! */ var playerStatus, /** * Button: Suggest joining table */ playerSuggestButton; /** * Player ELO * @type {number} */ var playerElo = 0; /** * Player ID. * Technically a number, but just using it to concatenate to a url * @type {string} */ var playerID = ""; // only proceed if there is an available players node if (availablePlayersNode) { availablePlayers = availablePlayersNode.childNodes; } else { console.log("availablePlayersNode not found."); return; } // show Stop Auto Suggest button, hide Auto Suggest button var autoSuggestButton = document.getElementById("autosuggest"); if (autoSuggestButton) autoSuggestButton.setAttribute("style", "display: none;"); var stopSuggestButton = document.getElementById("stopsuggest"); if (stopSuggestButton) stopSuggestButton.setAttribute("style", "display: inline;"); suggestPlayers = true; while (suggestPlayers) { console.log("current index is " + index + " out of " + availablePlayers.length); if (index >= availablePlayers.length) { index = 0; suggestPlayers = false; console.log("Finished. The next iteration is scheduled in 12 seconds."); interrupted = false; await sleep(12000); if (!interrupted) { loop(); } else { console.log("Auto suggestions process is interrupted by user."); } return; } // OLD WAY TO GET PLAYER ATTRIBUTES... playerID and playerName do not match sometimes with this method. //playerAttributes = availablePlayers[index].innerText.split("\n").map(attribute => attribute.trim()); //playerAttributes = availablePlayers[index].innerHTML; //playerName = playerAttributes[0]; //playerElo = parseInt(playerAttributes[1], 10); //playerID = availablePlayers[1].id.split("_")[1]; var parser = new DOMParser(); var playerHTML = parser.parseFromString(availablePlayers[index].innerHTML, "text/html"); // Example of what playerHTML could be: // <!DOCTYPE html> // <html> // <head> // <title></title> // </head> // <body> // <div class="\"availableplayername\""> // <a href="/"/#!player?id=34570376/"">saltyk9</a> // </div> // <div class="\"availableplayerrank\""> // <div class="\"gamerank"> // <span class="\"icon20"></span> <span class="\"gamerank_value\"">191</span> // </div> // <div class="\"imgtext" style="\"display:none\""></div> <i class="\"fa" id="\"sticky_avail_34570376\"" style="\"display:none\""></i> // </div> // <div class="\"availableplayertable\"" id="\"availableplayertable_34570376\"" style="\"display:"> // Seasons n°35897569 // </div> // <div class="\"availableplayersuggest\""> // <a class="\"bgabutton" href="/"#/"" id="\"suggestjoin_34570376\""><i class="\"fa"></i> Suggest to join table</a><span class="\"suggestsent\"" id="\"suggestsent_34570376\""><i class="\"fa"></i> Suggestion sent!</span> // </div> // </body> // </html> playerID = playerHTML.getElementsByTagName("a")[0].outerHTML.split("id=")[1].split('\">')[0]; playerName = playerHTML.getElementsByTagName("a")[0].innerText; playerElo = playerHTML.querySelector(".gamerank_value").innerText; playerStatus = document.getElementById("suggestsent_" + playerID); playerSuggestButton = document.getElementById("suggestjoin_" + playerID); // skip player if on the blacklist. if (blackList.indexOf(playerName) != -1) { console.log(playerName + " is skipped because player is on the blacklist."); index++; continue; } // skip player if the player has already been suggested to play on this table. if (alreadySuggested.indexOf(playerName) != -1) { console.log(playerName + " is skipped because player has already been suggested."); console.log(alreadySuggested); index++; continue; } // skip player if the player has already been suggested (probably manually prior to running this script) to play on this table. if (!isVisible(playerSuggestButton)) { console.log(playerName + " is skipped because player has already been suggested."); alreadySuggested.push(playerName); ++index; continue; } // skip if player does not meet minimum Elo. if (playerElo < minimumElo) { console.log(playerName + " is skipped because player's Elo (" + playerElo + ") is less than " + minimumElo + "."); index++; continue; } console.log("Suggestion is being sent to " + playerName + " (" + playerElo + "): " + playerID + "."); alreadySuggested.push(playerName); suggestPlayer(tableID, playerID); console.log("Waiting 5 seconds."); await sleep(6000); // actually waiting 6 seconds because bga is still giving 5 second warning when set to 5001. } } function suggestPlayer(tableID, playerID) { var fetchRequest = new Request("https://en.boardgamearena.com/gamelobby/gamelobby/suggest.html?table=" + tableID + "&player=" + playerID); var fetchInit = { method: 'GET', mode: 'cors', credentials: "include" }; // make sure to send credentials or you will get "you are not the admin" warnings. fetch(fetchRequest, fetchInit) .then(function(response) { return response.json(); }) .then(function(data) { console.log(data); if (data.status == "0") { console.log("BGA Error: " + data.error); } }) .catch(function(err) { console.log("Fetch Error: " + err); }); // Example Responses: // {"status":1,"data":"ok"} // {"status":"0","error":"You've already sent a suggestion to that player.","expected":1,"code":100} // {"status":"0","error":"You need to wait 5 seconds between two suggestions.","expected":1,"code":100} } function isVisible(elem) { return elem && (elem.offsetWidth !== 0 || elem.offsetHeight !== 0); } async function observeStartButton() { var startGameButton = document.getElementById("startgame"); if (!startGameButton) return; var enoughPlayers = false; while (!enoughPlayers) { await sleep(6000); enoughPlayers = isVisible(startGameButton); } if (!interrupted) { console.log("Automatically starting game."); startGameButton.click(); } } window.onload = function() { // tampermonkey doesn't support '#' in the url (see https://tampermonkey.net/documentation.php#_include), so check if on a table here before continuing. if (window.location.href.includes("#!table?table=")) { init(); } };