您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds helpful timers and links to the GC sidebar.
- // ==UserScript==
- // @name GC Helper
- // @description Adds helpful timers and links to the GC sidebar.
- // @version 0.3
- // @author ben (mushroom), dani
- // @match https://grundos.cafe/*
- // @match https://www.grundos.cafe/*
- // @icon https://www.google.com/s2/favicons?domain=grundos.cafe
- // @namespace https://greasyfork.org/users/727556
- // ==/UserScript==
- var storage;
- var fishingStorage;
- localStorage.getItem("trainingtrackerGC==") != null ? storage = JSON.parse(localStorage.getItem("trainingtrackerGC==")) : storage = {display: true, students: {}};
- localStorage.getItem("fishingtrackerGC==") != null ? fishingStorage = JSON.parse(localStorage.getItem("fishingtrackerGC==")) : fishingStorage = {display: true, pets: {}};
- var currentPage = window.location.href;
- var pageHTML = document.body.innerHTML;
- var documentText = document.body.innerText;
- var content = document.getElementsByClassName("content")[0];
- var currentDate = new Date();
- var usingDefaultTheme = document.body.innerHTML.indexOf('04/top_bar_anim') < 0 ? true : false;
- function trainingList() {
- // Loop through students in storage
- var newDate = new Date();
- for (var student in storage.students)
- {
- // get name, parse date, update content of
- let studentName = student;
- var endDate = new Date(storage.students[student].timeToCompletion);
- var timeString;
- if (!isNaN(Date.parse(endDate))) // check if valid date
- {
- var hoursLeft = Math.floor((endDate - newDate)/(1000*60*60));
- var minutesLeft = Math.floor(((endDate - newDate) % (1000*60*60)) / (1000*60));
- var secondsLeft = Math.floor(((endDate - newDate) % (1000*60)) / (1000));
- if (secondsLeft >= 0)
- {
- timeString = hoursLeft + "h " + minutesLeft + "m";
- }
- else
- {
- timeString = "Course Finished!";
- }
- }
- else
- {
- timeString = storage.students[student].timeToCompletion;
- }
- document.getElementById(studentName + "_ttc").innerText = timeString;
- }
- for (var fishingPet in fishingStorage.pets)
- {
- var endDateFish = new Date(fishingStorage.pets[fishingPet][0])
- var timeStringFish;
- if (!isNaN(Date.parse(endDateFish))) // check if valid date
- {
- var hoursLeftFish = Math.floor((endDateFish - newDate)/(1000*60*60));
- var minutesLeftFish = Math.floor(((endDateFish - newDate) % (1000*60*60)) / (1000*60));
- var secondsLeftFish = Math.floor(((endDateFish - newDate) % (1000*60)) / (1000));
- if (secondsLeftFish >= 0)
- {
- timeStringFish = hoursLeftFish + "h " + minutesLeftFish + "m";
- }
- else
- {
- timeStringFish = "🐟";
- }
- }
- document.getElementById(fishingPet + "_ttf").innerText = timeStringFish;
- }
- }
- (function() {
- 'use strict';
- // When on training status page, parse HTML & store in local storage
- if (currentPage == "https://www.grundos.cafe/island/training/?type=status"){
- var petTables = content.getElementsByTagName("table")[0].getElementsByTagName("tbody")[0].getElementsByTagName("tr");
- var numOfPets = petTables.length / 2;
- var petNames = [];
- // Loop through pets
- for (var i = 0; i < numOfPets; i++)
- {
- var courseInfo = petTables[2*i].getElementsByTagName("td")[0].getElementsByTagName("b")[0].innerText.split(" ");
- petNames.push(courseInfo[0]);
- // if last element of courseInfo == course, remove petname from students
- if (courseInfo[courseInfo.length - 1] == "course")
- {
- delete storage.students[courseInfo[0]];
- }
- // else, add student record (pet name, course, time to completion)
- else
- {
- var timeToCompletion = petTables[2*i + 1].getElementsByTagName("td")[1].getElementsByTagName("b")[0].innerText;
- if (timeToCompletion.indexOf("Codestone") > 0)
- {
- storage.students[courseInfo[0]] = {currentCourse: courseInfo[courseInfo.length - 1], timeToCompletion: timeToCompletion + " required"};
- }
- else if (timeToCompletion == "Course Finished!")
- {
- storage.students[courseInfo[0]] = {currentCourse: courseInfo[courseInfo.length - 1], timeToCompletion: timeToCompletion};
- }
- else
- {
- var re = /\d+/g;
- var timeParts = [...timeToCompletion.matchAll(re)];
- var endTime = new Date(currentDate.getTime() + timeParts[0]*60*60*1000 + timeParts[1]*60*1000 + timeParts[2]*1000)
- storage.students[courseInfo[0]] = {currentCourse: courseInfo[courseInfo.length - 1], timeToCompletion: endTime};
- }
- }
- }
- for (var s in storage.students)
- {
- var matchExists = 0;
- for (var j = 0; j < petNames.length; j++)
- {
- if (petNames[j] == s)
- {
- matchExists = 1;
- }
- }
- if (matchExists == 0)
- {
- delete storage.students[s];
- }
- }
- localStorage.setItem("trainingtrackerGC==", JSON.stringify(storage));
- }
- // When on fishing success page, parse HTML & store in local storage
- if (currentPage == "https://www.grundos.cafe/water/fishing/" && document.body.innerText.lastIndexOf('might be able to') > 0)
- {
- var activePet = usingDefaultTheme ? documentText.substring(documentText.lastIndexOf(' | Pet : ') + 9, documentText.lastIndexOf(' | NP : ')) : documentText.substring(documentText.lastIndexOf('\npet : ') + 7, documentText.lastIndexOf('\nNP : '))
- var hoursUntilNext = documentText.substring(documentText.lastIndexOf('might be able to cast again in about ') + 37, documentText.lastIndexOf('might be able to cast again in about ') + 38)
- var currentLevel = activePet in fishingStorage.pets ? fishingStorage.pets[activePet][1] : "TBD"
- if (documentText.lastIndexOf("fishing level increases to") > 0){
- const levRegex = /fishing level increases to (.*?)!/g;
- var levResult = levRegex.exec(documentText);
- currentLevel = levResult[1];
- }
- fishingStorage.pets[activePet] = [ new Date(currentDate.getTime() + 60*60*1000*parseInt(hoursUntilNext)) , currentLevel ]
- localStorage.setItem("fishingtrackerGC==", JSON.stringify(fishingStorage));
- }
- // When on any page with Neopets sidebar, add training module
- if (document.getElementsByName("a").length > 0)
- {
- var trainingModule = `<div class="tt" style="position:absolute; left:950px; top:240px; width: 140px;"><a href="https://www.grundos.cafe/island/training/?type=status" style='color:#FF8CA1'>Training:</a><br>`
- var studentCount = 0;
- // Loop through students in storage
- for (var student in storage.students)
- {
- let studentName = student;
- let currentCourse = storage.students[student].currentCourse;
- var endDate = new Date(storage.students[student].timeToCompletion);
- var timeString;
- if (!isNaN(Date.parse(endDate))) // check if valid date
- {
- if (Date.parse(endDate) > currentDate)
- {
- var hoursLeft = Math.floor((endDate - currentDate)/(1000*60*60));
- var minutesLeft = Math.floor(((endDate - currentDate) % (1000*60*60)) / (1000*60));
- var secondsLeft = Math.floor(((endDate - currentDate) % (1000*60)) / (1000));
- timeString = hoursLeft + "h " + minutesLeft + "m";
- }
- else
- {
- timeString = "Course Finished!";
- }
- }
- else
- {
- timeString = storage.students[student].timeToCompletion;
- }
- var trainingModulePart = `<li>${student} (<i>${currentCourse}</i>): <span id="${student}_ttc">${timeString}</span></li>`
- trainingModule = trainingModule + trainingModulePart;
- studentCount++;
- }
- if (studentCount == 0)
- {
- trainingModule = trainingModule + `<br>No pets in courses - go get started!`;
- }
- // Adding fishing
- var fishingDisplay = fishingStorage.display ? "inline" : "none";
- var fishingDisplayArrow = fishingStorage.display ? "↑" : "↓";
- trainingModule = trainingModule + `<br><a href="/water/fishing/" style='color:#FF8CA1'>Fishing:</a> <span style="font-size: 16px; cursor: pointer;" id="TBD">` + fishingDisplayArrow + `</span><div style="display:` + fishingDisplay + `;" id="fishingModulePets">`
- var fishingPetsArray = [];
- for (var pet in fishingStorage.pets)
- {
- if (!Array.isArray(fishingStorage.pets[pet])){
- var ph = fishingStorage.pets[pet]
- fishingStorage.pets[pet] = [ ph, "TBD" ]
- }
- fishingPetsArray.push([ pet, fishingStorage.pets[pet][0] ]);
- }
- fishingPetsArray.sort((a, b) => new Date(b[1]) - new Date(a[1]));
- for (var p = 0; p < fishingPetsArray.length; p++)
- {
- let petName = fishingPetsArray[p][0];
- let petLevel = fishingStorage.pets[petName][1];
- let nextFishingTime = new Date(fishingStorage.pets[petName][0]);
- var timeStringF;
- if (!isNaN(Date.parse(nextFishingTime))) // check if valid date
- {
- if (Date.parse(nextFishingTime) > currentDate)
- {
- var hoursLeftF = Math.floor((nextFishingTime - currentDate)/(1000*60*60));
- var minutesLeftF = Math.floor(((nextFishingTime - currentDate) % (1000*60*60)) / (1000*60));
- var secondsLeftF = Math.floor(((nextFishingTime - currentDate) % (1000*60)) / (1000));
- timeStringF = hoursLeftF + "h " + minutesLeftF + "m";
- }
- else
- {
- timeStringF = "🐟";
- }
- }
- var fishingModulePart = `<li><a style="font-size: 10px; color:#FF8CA1" href="/setactivepet/?pet_name=${petName}">${petName}</a> (${petLevel}): <span id="${petName}_ttf">${timeStringF}</span></li>`
- trainingModule = trainingModule + fishingModulePart;
- }
- trainingModule = trainingModule + `</div>`;
- document.getElementsByTagName("body")[0].insertAdjacentHTML("afterbegin", trainingModule)
- // Add on-click event
- document.getElementById("TBD").onclick = function() {
- fishingStorage.display = !fishingStorage.display;
- if (fishingStorage.display){
- console.log("hi")
- document.getElementById("TBD").innerText = "↑";
- document.getElementById("fishingModulePets").style.display = "inline";
- }
- else{
- console.log("bye")
- document.getElementById("TBD").innerText = "↓";
- document.getElementById("fishingModulePets").style.display = "none";
- }
- localStorage.setItem("fishingtrackerGC==", JSON.stringify(fishingStorage));
- };
- setInterval(trainingList, 1000);
- }
- // When on quickref, remove abandoned fishers
- const getPetNames = () => Array.from(document.querySelectorAll(`.quickref_content a[href*="/setactivepet/?pet_name="]`))
- .map(e => e.nextElementSibling.textContent)
- function pruneFishers() {
- const key = "fishingtrackerGC=="
- const actualPets = getPetNames()
- // Load saved fishing data
- let data = localStorage.getItem(key)
- if (!data) return // never visited the fishing module
- data = JSON.parse(data)
- // Remove pets that are no longer on the account
- const currentEntries = Object.entries(data.pets)
- const prunedEntries = currentEntries.filter(([fisher, _]) => actualPets.includes(fisher))
- // Quit if nothing changed
- const changed = prunedEntries.length < currentEntries.length
- if (!changed) return
- // Update and save
- data.pets = Object.fromEntries(prunedEntries)
- localStorage.setItem(key, JSON.stringify(data))
- }
- if (currentPage == "https://www.grundos.cafe/quickref/") {
- pruneFishers()
- }
- })();