[GC] - Underwater Fishing Data Logger

Fishing rewards sorting, logging and Discord Webhooks.

  1. // ==UserScript==
  2. // @name [GC] - Underwater Fishing Data Logger
  3. // @namespace Grundo's Cafe
  4. // @match https://www.grundos.cafe/water/fishing/
  5. // @grant GM.getValue
  6. // @grant GM.setValue
  7. // @grant GM.addStyle
  8. // @grant GM.notification
  9. // @grant GM.xmlHttpRequest
  10. // @version 1.3.7
  11. // @license MIT
  12. // @author Cupkait
  13. // @icon https://i.imgur.com/4Hm2e6z.png
  14. // @description Fishing rewards sorting, logging and Discord Webhooks.
  15. // @require https://update.gf.qytechs.cn/scripts/489454/1556136/%5BGC%5D%20-%20Underwater%20Fishing%20Prizes%20Library.js
  16. // ==/UserScript==
  17.  
  18.  
  19. const userName = /user=(.*?)"/g.exec(document.body.innerHTML)[1];
  20. const buttonFishAll = document.querySelector('input[value="Fish with Everyone!"]');
  21. const buttonFishOne = document.querySelector('input[value="Reel in Your Line"]');
  22. var webHooks = GM.getValue("webHooks", []);
  23.  
  24. if (window.location.href.endsWith('settings')) {
  25. document.querySelector('main').remove();
  26. }
  27.  
  28.  
  29. async function getCurrentPetLevels() {
  30. try {
  31. const response = await fetch("/quickref/");
  32. if (!response.ok) {
  33. throw new Error('Network response was not ok');
  34. }
  35. const html = await response.text();
  36. const parser = new DOMParser();
  37. const doc = parser.parseFromString(html, "text/html");
  38. const petList = doc.querySelector("#quickref_petlist").children;
  39. const petLevels = {};
  40.  
  41. Array.from(petList).forEach(pet => {
  42. const petrefName = pet.querySelector("a").getAttribute("href").match(/_name=(.*?)$/)[1];
  43. const petFishingLevel = pet.querySelectorAll("span")[12].textContent.match(/Fishing : (.*?)$/)[1];
  44. petLevels[petrefName] = petFishingLevel;
  45. });
  46.  
  47. sessionStorage.setItem('petLevels', JSON.stringify(petLevels));
  48.  
  49. } catch (error) {
  50. console.error("Error fetching data:", error);
  51. return null;
  52. }
  53. }
  54.  
  55. async function collectFishingResults() {
  56. let displayResults = document.createElement("div");
  57. displayResults.innerHTML = "Loading results... please wait.";
  58. displayResults.id = "displayResults";
  59. displayResults.style.cssText =
  60. "color: green; text-align: center; link-color:green; font-size:14px; font-weight:bold;";
  61. document.querySelector("div#page_content > main").insertAdjacentElement("beforebegin", displayResults);
  62.  
  63.  
  64.  
  65. const resultsList = document.querySelectorAll('.center-items');
  66. const resultsDiv = document.querySelector('.flex-column')
  67. let results = [];
  68. let highlights = false;
  69. const goodPrizes = document.createElement('div');
  70.  
  71.  
  72. if (resultsList.length > 0) {
  73.  
  74. displayResults.innerHTML = await `Your fishing results have been <a href="https://lookerstudio.google.com/reporting/ec18c798-ee62-4a7d-8315-5569c8de5ef6" target="_blank">submitted</a>.`;
  75. resultsList.forEach(result => {
  76. var name = result.querySelector('strong').textContent;
  77. var item = result.querySelector('p').textContent.match(/ a (.*?)!/)[1];
  78. var cooldown = result.querySelectorAll('strong')[1].textContent;
  79. var image = result.querySelectorAll('img')[1].src;
  80. var newlevel = result.querySelectorAll("p")[1].textContent.includes("fishing level") ? result.querySelectorAll("p")[1].textContent.match(/\d+/)[0] : null;
  81. var storedLevels = JSON.parse(sessionStorage.getItem('petLevels'));
  82. var oldlevel = storedLevels && storedLevels[name];
  83.  
  84. results.push({ name, item, cooldown, image, oldlevel, newlevel });
  85. sendResultToDatabase(name, oldlevel, newlevel, item, cooldown);
  86. const prize = prizes.find(prize => prize.item === item);
  87. if (prize) {
  88. highlights = true
  89. goodPrizes.append(result);
  90. generatePrizeWebhooks(name, oldlevel, item, image);
  91. } else {
  92. console.log("Prize sucked, no webhook sent.")
  93. };
  94. });
  95.  
  96. if (highlights === true) {
  97.  
  98. const fishingstyle = document.createElement('style');
  99. fishingstyle.innerHTML = `
  100. .center-items img {
  101. transform: translate3d(0, 0, 0);
  102. mix-blend-mode: multiply;
  103. }
  104. `;
  105.  
  106. //document.head.appendChild(fishingstyle);
  107. goodPrizes.classList.add("center-items");
  108. goodPrizes.style.backgroundColor = "#efef404f";
  109. goodPrizes.style.border = "2px solid black"
  110. resultsDiv.insertAdjacentElement('beforebegin', goodPrizes);
  111. }
  112.  
  113.  
  114. } else {
  115. const resultSingle = document.querySelector('#page_content .center');
  116.  
  117. if (resultSingle) {
  118. var name = document.querySelectorAll('#userinfo a')[2].textContent;
  119. var item = resultSingle.querySelector("img").alt;
  120. var cooldown = resultSingle.querySelector('strong').textContent;
  121. var image = resultSingle.querySelector('img').src;
  122. var newlevel = resultSingle.querySelectorAll("p")[1].textContent.includes("fishing level") ? resultSingle.querySelectorAll("p")[1].textContent.match(/\d+/)[0] : null;
  123. var storedLevels = JSON.parse(sessionStorage.getItem('petLevels'));
  124. var oldlevel = storedLevels && storedLevels[name];
  125.  
  126. results.push({ name, item, cooldown, image, oldlevel, newlevel });
  127. sendResultToDatabase(name, oldlevel, newlevel, item, cooldown);
  128. const prize = prizes.find(prize => prize.item === item);
  129. if (prize) {
  130. console.log("Valid prize identified.")
  131.  
  132. generatePrizeWebhooks(name, oldlevel, item, image);
  133. } else {
  134. console.log("Prize sucked, no webhook sent.")
  135. };
  136.  
  137. }}
  138.  
  139. }
  140.  
  141. // Only collect results if you've actually attempted to fish.
  142. if (document.referrer.endsWith("/water/fishing/") && document.querySelector('main').textContent.includes("You reel in your line and get")) {
  143. collectFishingResults();
  144. }
  145. //else {createFishHookSettings();}
  146.  
  147. // Only fetch current fishing levels when you click the button to fish.
  148. if (buttonFishOne || buttonFishAll) {
  149. document.addEventListener("click", async function(event) {
  150. if (event.target === buttonFishOne || event.target === buttonFishAll) {
  151. event.preventDefault();
  152. await getCurrentPetLevels();
  153. event.target.form.submit();
  154. }
  155. });
  156. }
  157.  
  158.  
  159. function getTimestamp() {
  160. const currentDate = new Date();
  161. const pstOffset = -8 * 60; // PST offset is UTC-8
  162. const timestampPST = new Date(currentDate.getTime() + pstOffset * 60 * 1000);
  163. return timestampPST.toISOString().replace("T", " ").replace("Z", "");
  164. }
  165.  
  166.  
  167.  
  168. async function sendResultToDatabase(name, oldlevel, newlevel, item, cooldown) {
  169. let opts = {
  170. mode: "no-cors",
  171. referrer: "no-referrer",
  172. headers: {
  173. "Content-Type": "application/x-www-form-urlencoded",
  174. },
  175. };
  176. const logResponse = `https://docs.google.com/forms/d/e/1FAIpQLSdBhJS1NSxHCmy32BqH0DEdQRJci1IVPOWUFcaothsiZjXu-w/formResponse?usp=pp_url&entry.886049257=${userName}&entry.343654154=${name}&entry.1922136733=${oldlevel}&entry.693447328=${newlevel}&entry.881968876=${item}&entry.303510013=${cooldown}&entry.1110645895=`;
  177. try {
  178. await fetch(logResponse, opts);
  179. } catch (error) {
  180. // Do nothing
  181. }
  182. }
  183.  
  184.  
  185. async function generatePrizeWebhooks(name, oldlevel, item, image) {
  186. console.log("Webhook generated.")
  187. const webHooks = await GM.getValue("webHooks", []);
  188.  
  189. const hook = {
  190. content: null,
  191. embeds: [
  192. {
  193. description:
  194. `${item}?\nWhat a great prize!`,
  195. color: 9356588,
  196. author: {
  197. name: `${userName} took ${name} fishing...`,
  198. },
  199. thumbnail: {
  200. url: `${image}`,
  201. },
  202. },
  203. ],
  204. username: "Underwater Fishing Prizes",
  205. avatar_url: "https://i.imgur.com/4Hm2e6z.png",
  206. attachments: [],
  207. };
  208.  
  209. for (const webhook of webHooks) {
  210. try {
  211. await sendMessage(hook, webhook);
  212. console.log("Message sent successfully.");
  213. } catch (error) {
  214. console.error("Error sending message:", error);
  215. }
  216. }
  217. }
  218.  
  219.  
  220. async function sendMessage(hook, webhook) {
  221. console.log("Webhook triggered.");
  222.  
  223. return new Promise((resolve, reject) => {
  224. GM.xmlHttpRequest({
  225. method: "POST",
  226. url: webhook,
  227. headers: {
  228. "Content-Type": "application/json"
  229. },
  230. data: JSON.stringify(hook),
  231. onload: function(response) {
  232. if (response.status >= 200 && response.status < 300) {
  233. resolve(response.responseText);
  234. } else {
  235. reject(new Error(`Request failed with status ${response.status}`));
  236. }
  237. },
  238. onerror: function(error) {
  239. reject(error);
  240. }
  241. });
  242. });
  243. }
  244.  
  245. async function createFishHookSettings() {
  246. const wrapperContainer = document.createElement("div");
  247. wrapperContainer.id = "wrapContainer";
  248. wrapperContainer.style.position = "relative";
  249. wrapperContainer.style.borderBottom = "3px solid";
  250. wrapperContainer.style.padding = "5px 10px 5px 0px";
  251. wrapperContainer.style.height = "30px";
  252. wrapperContainer.style.width = "100%";
  253. wrapperContainer.style.top = "0px";
  254. wrapperContainer.style.left = "0px";
  255. wrapperContainer.style.backgroundColor = "#d2d0cc";
  256. wrapperContainer.style.boxShadow = "5px 0 5px rgba(0, 0, 0, 0.5)";
  257.  
  258. const wrapperSettings = document.createElement("button");
  259. wrapperSettings.textContent = "Fish Hook Settings";
  260. wrapperSettings.id = "wrapSettings";
  261. wrapperSettings.style.position = "relative";
  262. wrapperSettings.style.fontSize = "12px";
  263. wrapperSettings.style.fontWeight = "bold";
  264. wrapperSettings.style.fontFamily = "courier";
  265. wrapperSettings.style.padding = "0px";
  266. wrapperSettings.style.width = "100%";
  267. wrapperSettings.style.height = "auto";
  268. wrapperSettings.style.border = "1px solid rgb(204, 204, 204)";
  269. wrapperSettings.style.cursor = "pointer";
  270. wrapperSettings.style.backgroundColor = "transparent";
  271.  
  272. const wrapperMenu = document.createElement("div");
  273. wrapperMenu.id = "wrapMenu";
  274. wrapperMenu.style.display = "none";
  275. wrapperMenu.style.borderRadius = "15px 15px 15px 0px";
  276. wrapperMenu.style.borderBottom = "3px solid";
  277. wrapperMenu.style.position = "absolute";
  278. wrapperMenu.style.width = "200px";
  279. wrapperMenu.style.height = "250px";
  280. wrapperMenu.style.bottom = "0%";
  281. wrapperMenu.style.left = "100%";
  282. wrapperMenu.style.margin = "-3px";
  283. wrapperMenu.style.padding = "10px";
  284. wrapperMenu.style.backgroundColor = "#d2d0cc";
  285. wrapperMenu.style.boxShadow = "5px 0 5px rgba(0, 0, 0, 0.5)";
  286.  
  287. const firstButton = document.createElement("button");
  288. firstButton.textContent = "Add a Webhook";
  289. firstButton.id = "menubutton";
  290. firstButton.style.height = "35px";
  291. firstButton.style.width = "98%";
  292. firstButton.style.margin = "5px 3px";
  293. firstButton.style.backgroundColor = "transparent";
  294. firstButton.style.borderRadius = "5px";
  295. firstButton.style.boxShadow = "5px 0 5px rgba(0, 0, 0, 0.5)";
  296. firstButton.addEventListener("click", addWebhook);
  297.  
  298. wrapperMenu.appendChild(firstButton);
  299. wrapperContainer.appendChild(wrapperSettings);
  300. wrapperContainer.appendChild(wrapperMenu);
  301. document.getElementById("sb_edge").appendChild(wrapperContainer);
  302.  
  303. wrapperSettings.addEventListener("click", () => {
  304. wrapperMenu.style.display = wrapperMenu.style.display === "none" ? "block" : "none";
  305. });
  306.  
  307. async function addWebhook() {
  308. var newWebhook = prompt(
  309. "Paste one webhook URL to add to your script.\n\nIf you want to add multiple, do one at a time."
  310. );
  311. if (newWebhook) {
  312. let webHooks = await GM.getValue("webHooks", []);
  313. if (!Array.isArray(webHooks)) {
  314. webHooks = [];
  315. }
  316. webHooks = [...new Set(webHooks)];
  317. if (!webHooks.includes(newWebhook)) {
  318. webHooks.push(newWebhook);
  319. await GM.setValue("webHooks", webHooks);
  320. alert("Webhook added successfully!");
  321. } else {
  322. webHooks = [...new Set(webHooks)];
  323. await GM.setValue("webHooks", webHooks);
  324.  
  325. alert("This webhook URL is already added.");
  326. }
  327. }
  328. }
  329.  
  330.  
  331. GM.addStyle(`
  332. #wrapContainer, #wrapSettings, #wrapMenu {
  333. background-color: #d2d0cc;
  334. }
  335. #wrapSettings {
  336. cursor: pointer;
  337. }
  338. #wrapMenu {
  339. display: none;
  340. border-radius: 15px 15px 15px 0px;
  341. border-bottom: 3px solid;
  342. position: absolute;
  343. width: 200px;
  344. height: 250px;
  345. bottom: 0%;
  346. left: 100%;
  347. margin: -3px;
  348. padding: 10px;
  349. box-shadow: 5px 0 5px rgba(0, 0, 0, 0.5);
  350. }
  351. `);
  352.  
  353. }
  354. createFishHookSettings();
  355.  
  356.  
  357.  
  358.  
  359. GM.addStyle(`
  360.  
  361. #hookButton {
  362. width: 480px;
  363. height:20px;
  364. display: flex;
  365. justify-content: flex-end;
  366. }
  367.  
  368. `);
  369.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址