RoSearcher

Find roblox servers at the click of a button.

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
  1. // ==UserScript==
  2. // @name RoSearcher
  3. // @namespace http://tampermonkey.net/
  4. // @version 1
  5. // @description Find roblox servers at the click of a button.
  6. // @author https://github.com/NotDSF
  7. // @match https://*.roblox.com/games/*
  8. // @icon https://www.google.com/s2/favicons?domain=roblox.com
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. let Cookie = document.cookie.match(/rosearch=(?<json>{.*?});/);
  16. let Options = Cookie?.groups.json ? JSON.parse(Cookie?.groups.json) : {};
  17. let Version = "0.5";
  18. let GameID = document.URL.match(/games\/(\d+)\//)[1];
  19. let GameOptions = Options[GameID] || {};
  20.  
  21. function GetServers(Index) {
  22. return new Promise((resolve, reject) => {
  23. fetch(`https://www.roblox.com/games/getgameinstancesjson?placeId=${GameID}&startIndex=${Index}&_=1`, {
  24. method: "GET",
  25. })
  26. .then(res => res.text())
  27. .then(json => resolve(JSON.parse(json)))
  28. .catch(er => reject(er));
  29. });
  30. }
  31.  
  32. function SaveOptions() {
  33. let Status = document.getElementById("server-status");
  34. let MaxPing = document.getElementById("ping-box").value;
  35. let MaxPlayers = document.getElementById("player-box").value;
  36. let CookieData = {};
  37. if (MaxPing.length) CookieData.MaxPing = MaxPing;
  38. if (MaxPlayers.length) CookieData.MaxPlayers = MaxPlayers;
  39.  
  40. let StatusBackup = Status.innerHTML;
  41. Options[GameID] = CookieData;
  42. Status.innerHTML = "Saved options!";
  43. document.cookie = `rosearch=${JSON.stringify(Options)}; path=/games; expires=Fri, 31 Dec 9999 23:59:59 GMT;`;
  44.  
  45. setTimeout(() => Status.innerHTML = StatusBackup, 2000);
  46. }
  47.  
  48. fetch("https://raw.githubusercontent.com/NotDSF/RoSearcher/main/script-version")
  49. .then(res => res.text())
  50. .then(body => {
  51. if (body.trim() !== Version) {
  52. if (confirm("A new version of RoSearch is available, would you like to download it?")) {
  53. document.location.href = "https://greatest.deepsurf.us/en/scripts/430402-rosearcher";
  54. }
  55. }
  56. })
  57. .catch(er => {
  58. alert("RoSearcher Error: " + er.toString());
  59. throw er;
  60. });
  61.  
  62. let GameInstances = document.getElementById("game-instances");
  63. let ParentDiv = document.createElement("div");
  64. let ContainerHead = document.createElement("div");
  65.  
  66. ParentDiv.className = "stack";
  67. GameInstances.prepend(ParentDiv);
  68.  
  69. // container header
  70.  
  71. let Title = document.createElement("h3");
  72. Title.innerHTML = "RoSearch";
  73.  
  74. ContainerHead.className = "container-header";
  75. ContainerHead.prepend(Title);
  76.  
  77. // container children
  78.  
  79. let pingbox = document.createElement("textarea");
  80. pingbox.className = "dialog-input ng-valid ng-isolate-scope ng-touched ng-not-empty ng-dirty ng-valid-parse";
  81. pingbox.rows = 1;
  82. pingbox.style = "overflow: hidden; overflow-wrap: break-word; resize: none; height: 30px; margin-bottom: 5px; display: inherit; border-radius: 3px; width: 330px;";
  83. pingbox.placeholder = "Max Ping (Leave Blank For Default)";
  84. pingbox.innerHTML = GameOptions.MaxPing || "";
  85. pingbox.id = "ping-box";
  86.  
  87. let maxPlayer = document.createElement("textarea");
  88. maxPlayer.className = "dialog-input ng-valid ng-isolate-scope ng-touched ng-not-empty ng-dirty ng-valid-parse";
  89. maxPlayer.rows = 1;
  90. maxPlayer.style = "overflow: hidden; overflow-wrap: break-word; resize: none; height: 30px; margin-bottom: 5px; display: inherit; border-radius: 3px; width: 330px;";
  91. maxPlayer.placeholder = "Max Players (Leave Blank For Default)";
  92. maxPlayer.innerHTML = GameOptions.MaxPlayers || "";
  93. maxPlayer.id = "player-box";
  94. let status = document.createElement("span");
  95. status.className = "section-content-off";
  96. status.id = "server-status";
  97. status.style = "display: inherit;";
  98.  
  99. async function main() {
  100. if (!confirm("Are you sure you want to find the server?")) return;
  101.  
  102. let Stats = document.getElementsByClassName("game-stat game-stat-width");
  103. let MaxPing = pingbox.value.length ? parseInt(pingbox.value) : 300;
  104. let MaxPlayers = maxPlayer.value.length ? parseInt(maxPlayer.value) : 4;
  105. let MaxServerP = parseInt(Stats[5].children[1].innerText);
  106. let ActiveP = parseInt(Stats[0].children[1].innerText.replace(",", ""));
  107. let Iterator = Math.floor(ActiveP / (MaxServerP * 9));
  108. console.log(MaxPing, MaxPlayers, Iterator);
  109. status.innerHTML = "Looking for servers...";
  110.  
  111. while (true) {
  112. let Servers = await GetServers(Iterator);
  113. let Matched = Servers.Collection.filter((server) => server.CurrentPlayers.length <= MaxPlayers && server.Ping <= MaxPing).shift();
  114.  
  115. if (Matched) {
  116. status.innerHTML = `Found server! Players: ${Matched.CurrentPlayers.length} Ping: ${Matched.Ping} Index: ${Iterator}`;
  117. eval(Matched.JoinScript);
  118. break;
  119. }
  120.  
  121. status.innerHTML = `Index: ${Iterator}.`;
  122. Iterator += Math.floor(ActiveP / (MaxServerP * 9));
  123. }
  124. }
  125.  
  126. let fakeButton = document.createElement("span");
  127. fakeButton.className = "btn-secondary-md btn-more";
  128. fakeButton.innerHTML = "Find Server";
  129. fakeButton.onclick = main;
  130. fakeButton.style = "display: inherit; width: min-content; margin-bottom: 20px;";
  131.  
  132. let fakeButton2 = document.createElement("span");
  133. fakeButton2.className = "btn-secondary-md btn-more";
  134. fakeButton2.innerHTML = "Save Options";
  135. fakeButton2.onclick = SaveOptions;
  136. fakeButton2.style = "display: inherit; width: min-content; margin-bottom: 5px;";
  137.  
  138. ParentDiv.prepend(ContainerHead, maxPlayer, pingbox, fakeButton2, fakeButton, status);
  139. })();