Sketchful Auto Join

Right-click on a full lobby to auto-refresh and join when there's a spot available.

  1. // ==UserScript==
  2. // @name Sketchful Auto Join
  3. // @namespace https://greasyfork.org/users/281093
  4. // @match https://sketchful.io/*
  5. // @grant none
  6. // @version 1.2
  7. // @author Bell
  8. // @description Right-click on a full lobby to auto-refresh and join when there's a spot available.
  9. // jshint esversion: 6
  10. // ==/UserScript==
  11.  
  12. const refreshInterval = 500; // Refresh interval, in milliseconds
  13.  
  14. (function requestPermission() {
  15. if (Notification.permission === "granted") {
  16. console.log("Notifications allowed, Sketchful Auto Join loaded");
  17. } else {
  18. Notification.requestPermission()
  19. .then(result => {
  20. console.log(result);
  21. });
  22. }
  23. })();
  24.  
  25. window.onfocus = () => {
  26. sessionStorage.setItem('tabFocus', '1');
  27. };
  28.  
  29. window.onblur = () => {
  30. sessionStorage.setItem('tabFocus', '0');
  31. };
  32.  
  33. const lobbiesTable = document.querySelector("#menuLobbiesTable");
  34. const menuNav = document.querySelector("#menu > div.menuNav > ul");
  35. let refreshing = false;
  36.  
  37. const config = {
  38. attributes: false,
  39. childList: true,
  40. subtree: true
  41. };
  42.  
  43. const onLobbyRefresh = function(mutationsList, observer) {
  44. for (let mutation of mutationsList) {
  45. let newNode = mutation.addedNodes[0];
  46. if (newNode.classList.contains("table")) {
  47. updateLobbies(newNode.querySelectorAll(".menuLobbiesRoom"));
  48. }
  49. }
  50. };
  51.  
  52. const lobbyObserver = new MutationObserver(onLobbyRefresh);
  53.  
  54. lobbyObserver.observe(lobbiesTable, config);
  55.  
  56. lobbiesTable.addEventListener("contextmenu", setActiveLobby, false);
  57. lobbiesTable.addEventListener("click", clearActiveLobby, false);
  58. menuNav.addEventListener("click", clearActiveLobby, true);
  59.  
  60. let activeLobby = null;
  61.  
  62. function setActiveLobby(e) {
  63. e.preventDefault();
  64. let lobby = e.target.parentNode;
  65. try {
  66. const hash = getLobbyHash(lobby);
  67. if (!activeLobby && isLobbyFull(lobby)) {
  68. activeLobby = hash;
  69. refreshLobbies();
  70. } else {
  71. clearActiveLobby();
  72. }
  73. } catch (error) {
  74. clearActiveLobby();
  75. }
  76. }
  77.  
  78. function clearActiveLobby() {
  79. if (activeLobby) {
  80. activeLobby = null;
  81. window.clearTimeout(this.refreshingID);
  82. refreshLobbies();
  83. }
  84. }
  85.  
  86. function refreshLobbies() {
  87. document.querySelector("#menuLobbiesRefresh").click();
  88. }
  89.  
  90. function isLobbyFull(lobby) {
  91. const capacity = getLobbyCapacity(lobby);
  92. return capacity.current >= capacity.max;
  93. }
  94.  
  95. function getLobbyCapacity(lobby) {
  96. const capacityRegexp = /<td>(\d+)\/(\d+)<\/td>/;
  97. const capacityMatch = lobby.innerHTML.match(capacityRegexp);
  98.  
  99. return {
  100. current: parseInt(capacityMatch[1]),
  101. max: parseInt(capacityMatch[2])
  102. };
  103. }
  104.  
  105. function getLobbyHash(lobby) {
  106. const hashRegexp = /lobbyConnect\([^#]+(#[\w]+)/;
  107. return lobby.outerHTML.match(hashRegexp)[1];
  108. }
  109.  
  110. function notify() {
  111. if (Notification.permission === "granted") {
  112. let notification = new Notification("Joined", {
  113. icon: "https://sketchful.io/res/logo/pencils%20optimized.png",
  114. body: "Click the notification to return to the game.",
  115. requireInteraction: true,
  116. });
  117.  
  118. notification.onclick = function() {
  119. window.focus();
  120. notification.close();
  121. };
  122. } else {
  123. console.log("Notifications are blocked.");
  124. }
  125. }
  126.  
  127. function tryToJoin(lobby) {
  128. if (isLobbyFull(lobby)) {
  129. console.log(activeLobby + " is full, refreshing");
  130. console.log(getLobbyCapacity(lobby));
  131. this.refreshingID = window.setTimeout(refreshLobbies, refreshInterval);
  132. } else {
  133. console.log("Joining " + activeLobby);
  134. lobbyConnect(activeLobby);
  135. let focus = parseInt(sessionStorage.getItem('tabFocus'));
  136. console.log("AUOT JOIN NOTIFIC", focus);
  137. if (!focus) {
  138. notify();
  139. }
  140. clearActiveLobby();
  141. }
  142. }
  143.  
  144. function updateLobbies(lobbies) {
  145. if (activeLobby) {
  146. for (let lobby of lobbies) {
  147. if (getLobbyHash(lobby) === activeLobby) {
  148. lobby.style.backgroundColor = "pink";
  149. tryToJoin(lobby);
  150. }
  151. }
  152. } else {
  153. console.log("No active lobby");
  154. }
  155. }