您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Notify when various Final Earth Timers are over and for troop movements.
// ==UserScript== // @name Final Earth Notifier // @namespace http://tampermonkey.net/ // @version 1.1.2 // @description Notify when various Final Earth Timers are over and for troop movements. // @author Natty_Boh // @include https://www.finalearth.com/* // @include https://finalearth.com/* // @grant GM_notification // @grant GM.xmlHttpRequest // @grant GM.getValue // @grant GM.setValue // @connect finalearth.com // ==/UserScript== 'use strict'; setTimeout(getApi, 600); setTimeout(addButton, 500) //check for and insert script settings link on HQ page menu bar function addButton() { if (!document.getElementById('script-settings-button') && document.querySelector(".hq_new")) { let elem = document.querySelector ( '.hq_new > #banner > .menu_cont' ) let button = `<span class="hover-span" id="script-settings-button">Script Settings</span>` if(elem) { elem.insertAdjacentHTML('afterbegin', button); const settingsButton = document.getElementById('script-settings-button'); settingsButton.addEventListener('click', function () { showScriptSettings() }); } } setTimeout(addButton, 500) } //insert script settings form over existing content function showScriptSettings() { let elem = document.querySelector ( '.hq_new' ) elem.innerHTML = ""; elem.insertAdjacentHTML('beforebegin', html); populateExistingSettings() const settingsButton = document.getElementById('saveSettingsButton'); settingsButton.addEventListener('click', function () { setSettings() }); } //save settings and redirect to HQ page so normal content will show again async function setSettings() { await GM.setValue("apiKey", document.getElementById('settingKey').value) await GM.setValue("warTimerNotif", document.getElementById('warCheckbox').checked) await GM.setValue("queueNotif", document.getElementById('trainCheckbox').checked) await GM.setValue("reimbNotif", document.getElementById('reimbCheckbox').checked) await GM.setValue("eventNotif", document.getElementById('eventCheckbox').checked) await GM.setValue("mailNotif", document.getElementById('mailCheckbox').checked) await GM.setValue("countryNotif", buildCountryNotifSettings()) await GM.setValue("userTeam", userTeam); await GM.setValue("currLocationNotif", document.getElementById('myLocation').checked) await GM.setValue("currLocationCD", document.getElementById('locationCD').value) window.location.href = '/HQ'; } //prefill form with the existing settings async function populateExistingSettings() { document.getElementById('settingKey').value = await GM.getValue("apiKey", ""); document.getElementById('warCheckbox').checked = await GM.getValue("warTimerNotif", false); document.getElementById('trainCheckbox').checked = await GM.getValue("queueNotif", false); document.getElementById('reimbCheckbox').checked = await GM.getValue("reimbNotif", false); document.getElementById('eventCheckbox').checked = await GM.getValue("eventNotif", false); document.getElementById('mailCheckbox').checked = await GM.getValue("mailNotif", false); document.getElementById('myLocation').checked = await GM.getValue("currLocationNotif", false); document.getElementById('locationCD').value = await GM.getValue("currLocationCD", 5); populateCountryNotifSettings() } function buildCountryNotifSettings() { var setting = { countryId: document.getElementById('countrySelector').value, axis: document.getElementById('axisCheck').checked, allies: document.getElementById('alliesCheck').checked, cooldown: document.getElementById('notifCD').value }; return setting; } async function populateCountryNotifSettings() { var countryNotif = await GM.getValue("countryNotif", { countryId: 0, axis: false, allies: false, cooldown: 5 }); document.getElementById('countrySelector').value = countryNotif.countryId document.getElementById('axisCheck').checked = countryNotif.axis document.getElementById('alliesCheck').checked = countryNotif.allies document.getElementById('notifCD').value = countryNotif.cooldown } //make api call every 30 seconds and call functions to check timer statuses async function getApi(){ var api = await GM.getValue("apiKey", "") if(api != "") { let url = 'http://www.finalearth.com/api/notifications?key=' + api GM.xmlHttpRequest({ method: 'GET', url: url, onload: function (response) { if (response.status == '200') { var json = JSON.parse(response.responseText) if (json.reason === "invalid-api-key") { console.log("Invalid api key, please add correct api key to script") } else { checkSettingsAndCallChecks(json) } } else { console.log("Something went wrong") } }, onerror: function (error) { console.log('Something went wrong, please let Natty_Boh know') } }) setTimeout(getApi, 30000); } else { console.log("No api key provided, please add correct api key to script") } } //check setting flags and call the relevant checks async function checkSettingsAndCallChecks(json) { if (await GM.getValue("warTimerNotif", false)) { await warCheck(json.data.timers.war) } if (await GM.getValue("queueNotif", false)) { await trainingCheck(json.data.timers.statistics, json.data.training.queued.length) } if (await GM.getValue("reimbNotif", false)) { await reimbCheck(json.data.timers.reimbursement) } if (await GM.getValue("eventNotif", false)) { await checkEvent(json.data.unreadEvents) } if (await GM.getValue("mailNotif", false)) { await checkMail(json.data.unreadMails) } var countryObj = await GM.getValue("countryNotif", {countryId: 0,axis: false,allies: false,cooldown: 5 }); var monitorLocation = await GM.getValue("currLocationNotif", false) if(monitorLocation) { getCountry(currentCountry => getWorldAndCheckTroops(countryObj, currentCountry)); } else if (countryObj) { getWorldAndCheckTroops(countryObj, undefined); } } async function warCheck(war) { var warTimer = await GM.getValue("warTimer", 0); if (timerEndedRecently(war, Date.now()/1000) && warTimer != war) { GM_notification ( {title: 'War timer up!', text: 'Your Final Earth war timer is over.'} ); console.log("Notifcation Sent!") await GM.setValue("warTimer", war); } } async function trainingCheck(trainEndTime, trainQueue) { var trainingTimer = await GM.getValue("trainingTimer", 0); if (timerEndedRecently(trainEndTime, Date.now()/1000) && trainingTimer != trainEndTime && trainQueue == 0) { GM_notification ( {title: 'Training queue empty!', text: 'Your Final Earth stat training queue is empty.'} ); console.log("Notifcation Sent!") await GM.setValue("trainingTimer", trainEndTime); } } async function reimbCheck(reimb) { var reimbTimer = await GM.getValue("reimbTimer", 0); if (timerEndedRecently(reimb, Date.now()/1000) && reimbTimer != reimb) { GM_notification ( {title: 'Reimbursement ready!', text: 'Your Final Earth reimbursement is ready.'} ); console.log("Notifcation Sent!") await GM.setValue("reimbTimer", reimb); } } async function checkEvent(unread) { var getNotified = await GM.getValue("eventNotified", false) if (unread != 0 && getNotified == false) { GM_notification ( {title: 'New event!', text: 'You have a new event in Final Earth'} ); console.log("Notifcation Sent!") await GM.setValue("eventNotified", true); } else if (unread == 0) { await GM.setValue("eventNotified", false); } } async function checkMail(unread) { var getMailNotified = await GM.getValue("mailNotified", false) if (unread != 0 && getMailNotified == false) { GM_notification ( {title: 'New message!', text: 'You have a new message in Final Earth'} ); console.log("Notifcation Sent!") await GM.setValue("mailNotified", true); } else if (unread == 0) { await GM.setValue("mailNotified", false); } } //only notify if the timer has ended in the last 60 seconds function timerEndedRecently(timer, now) { if (timer < now && now - timer <= 60) { return true } return false } //make world api call and call function to check troops async function getWorldAndCheckTroops(countrySettings, currentCountry) { var api = await GM.getValue("apiKey", "") if(countrySettings.countryId != 0) { let url = 'http://www.finalearth.com/api/world?key=' + api GM.xmlHttpRequest({ method: 'GET', url: url, onload: function (response) { if (response.status == '200') { var json = JSON.parse(response.responseText) getCountriesToCheck(json, countrySettings, currentCountry) } }, onerror: function (error) { console.log('Something went wrong') } }) } else { getCountriesToCheck(undefined, countrySettings, currentCountry) } } //check all countries async function getCountriesToCheck(json, countrySettings, currentCountry) { if (json) { json.data.forEach(country => processCountry(country, currentCountry ? currentCountry.data.id : -1, countrySettings)); } else { processCountry(currentCountry.data, currentCountry.data.id, countrySettings) } } //special handling for current country and monitored country async function processCountry(country, currentCountry, countrySettings) { var countryId = countrySettings.countryId var cooldown = await GM.getValue("currLocationCD", 5) if (countryId != 0 && country.id == countryId) { checkTroops(country, countryId, countrySettings.axis, countrySettings.allies, countrySettings.cooldown * 60); } else if (country.id == currentCountry) { if (await GM.getValue("userTeam") == "Allies") { checkTroops(country, currentCountry, true, false, cooldown * 60 ); } else { checkTroops(country, currentCountry, false, true, cooldown * 60 ); } } else { checkTroops(country, country.id, false, false, countrySettings.cooldown ? countrySettings.cooldown *60 : cooldown * 60); } } //get old troops and save new value + notify (yes I know this is gross soz I'll fix eventually) async function checkTroops(data, countryId, axisFlag, alliesFlag, cooldown) { var country = JSON.parse(await GM.getValue("country" + countryId, JSON.stringify(countryConstructor(0, 0, 0, 0)))) var axisCount = data.units.axis; var alliesCount = data.units.allies; var now = Date.now()/1000 if(axisFlag && axisCount != country.axisCount && parseInt(now) - country.notifiedTs >= cooldown) { var change = data.units.axis - country.axisCount; var countryName = data.name GM_notification ( {title: 'Unit change detected!', text: 'Axis troops in ' + countryName + ' have changed by ' + change + ' units'} ); var newCountry = countryConstructor(countryId, axisCount, alliesCount, now) await GM.setValue("country" + countryId, JSON.stringify(newCountry)) } if(alliesFlag && alliesCount != country.alliesCount && now - country.notifiedTs >= cooldown) { var change2 = data.units.allies - country.alliesCount; var countryName2 = data.name GM_notification ( {title: 'Unit change detected!', text: 'Allies troops in ' + countryName2 + ' have changed by ' + change2 + ' units'} ); var newCountry2 = countryConstructor(countryId, axisCount, alliesCount, now) await GM.setValue("country" + countryId, JSON.stringify(newCountry2)) } if (!alliesFlag && !axisFlag) { var newCountry3 = countryConstructor(countryId, axisCount, alliesCount, now-cooldown) await GM.setValue("country" + countryId, JSON.stringify(newCountry3)) } } //build country notification object function countryConstructor(id, axis ,allies, ts) { var country = { countryId: id, axisCount: axis, alliesCount: allies, notifiedTs: ts } return country; } //make country api call and return country id async function getCountry(callback) { var api = await GM.getValue("apiKey", "") let url = 'http://www.finalearth.com/api/country?key=' + api GM.xmlHttpRequest({ method: 'GET', url: url, onload: function (response) { if (response.status == '200') { var json = JSON.parse(response.responseText) callback(json) } }, onerror: function (error) { console.log('Something went wrong') } }) } let html = `<div class="bigdiv" style="height:100%; overflow-y:auto;"><form id="frm1" style="padding-top: 25px"> API key: <input type="text" id="settingKey"><br><br> <h2>Timer Notification Settings</h2> <input type="checkbox" id="warCheckbox"> War timer notifications <br> <input type="checkbox" id="trainCheckbox"> Empty training queue notifications <br> <input type="checkbox" id="mailCheckbox"> New Mail notifications <br> <input type="checkbox" id="eventCheckbox"> New Event notifications <br> <input type="checkbox" id="reimbCheckbox"> Reimbursement ready notifications <br> <br><br> </form> <h2 style=" text-align: center">Current Location Monitoring</h2> <br> <input type="checkbox" id="myLocation"> Notify for enemy unit changes in my current location<br> <br> Max Notification Frequency <input type="text" id="locationCD"> Minutes<br> <p>*Note: You will get notification immediately after a unit count change, this is a 'cooldown' to prevent notification spam if lots of changes occur quickly. </p><br> <h2 style=" text-align: center">Unit Change Monitoring</h2> <br> Specific country to monitor <select id="countrySelector" name="country"> <option value="0">No country monitoring</option> <option value="1">Afghanistan</option> <option value="2">Albania</option> <option value="3">Algeria</option> <option value="209">Andorra</option> <option value="5">Angola</option> <option value="6">Anguilla</option> <option value="7">Argentina</option> <option value="8">Armenia</option> <option value="9">Aruba</option> <option value="10">Australia</option> <option value="11">Austria</option> <option value="12">Azerbaijan</option> <option value="13">Bahamas</option> <option value="14">Bahrain</option> <option value="15">Bangladesh</option> <option value="16">Barbados</option> <option value="17">Belarus</option> <option value="18">Belgium</option> <option value="19">Belize</option> <option value="20">Benin</option> <option value="21">Bermuda</option> <option value="22">Bhutan</option> <option value="23">Bolivia</option> <option value="203">Bosnia</option> <option value="24">Botswana</option> <option value="25">Bouvet Island</option> <option value="26">Brazil</option> <option value="27">Brunei</option> <option value="28">Bulgaria</option> <option value="29">Burkina Faso</option> <option value="30">Burundi</option> <option value="31">Cambodia</option> <option value="32">Cameroon</option> <option value="33">Canada</option> <option value="34">Cape Verde</option> <option value="35">Cayman Islands</option> <option value="204">Central African Republic</option> <option value="36">Chad</option> <option value="37">Chile</option> <option value="38">China</option> <option value="39">Colombia</option> <option value="40">Comoros</option> <option value="41">Costa Rica</option> <option value="42">Croatia</option> <option value="43">Cuba</option> <option value="44">Cyprus</option> <option value="45">Czech Republic</option> <option value="205">Democratic Rep. of Congo</option> <option value="46">Denmark</option> <option value="47">Djibouti</option> <option value="48">Dominica</option> <option value="206">Dominican Republic</option> <option value="207">East Timor</option> <option value="49">Ecuador</option> <option value="50">Egypt</option> <option value="51">El Salvador</option> <option value="52">Equatorial Guinea</option> <option value="53">Eritrea</option> <option value="54">Estonia</option> <option value="55">Ethiopia</option> <option value="56">Falkland Islands</option> <option value="57">Faroe Islands</option> <option value="58">Fiji</option> <option value="59">Finland</option> <option value="60">France</option> <option value="61">Gabon</option> <option value="62">Gambia</option> <option value="63">Georgia</option> <option value="64">Germany</option> <option value="65">Ghana</option> <option value="66">Gibraltar</option> <option value="67">Greece</option> <option value="68">Greenland</option> <option value="69">Grenada</option> <option value="70">Guam</option> <option value="71">Guatemala</option> <option value="72">Guinea</option> <option value="73">Guinea Bissau</option> <option value="74">Guyana</option> <option value="75">Haiti</option> <option value="76">Holy See</option> <option value="77">Honduras</option> <option value="78">Hong Kong</option> <option value="79">Hungary</option> <option value="80">Iceland</option> <option value="81">India</option> <option value="82">Indonesia</option> <option value="83">Iran</option> <option value="84">Iraq</option> <option value="85">Ireland</option> <option value="86">Israel</option> <option value="87">Italy</option> <option value="210">Ivory Coast</option> <option value="88">Jamaica</option> <option value="89">Japan</option> <option value="90">Jordan</option> <option value="221">Karabakh</option> <option value="91">Kazakhstan</option> <option value="92">Kenya</option> <option value="93">Kiribati</option> <option value="222">Kosovo </option> <option value="94">Kuwait</option> <option value="95">Kyrgyzstan</option> <option value="96">Laos</option> <option value="97">Latvia</option> <option value="98">Lebanon</option> <option value="99">Lesotho</option> <option value="100">Liberia</option> <option value="101">Libya</option> <option value="102">Liechtenstein</option> <option value="103">Lithuania</option> <option value="104">Luxembourg</option> <option value="105">Macau</option> <option value="106">Macedonia</option> <option value="107">Madagascar</option> <option value="108">Malawi</option> <option value="109">Malaysia</option> <option value="110">Maldives</option> <option value="111">Mali</option> <option value="112">Malta</option> <option value="113">Marshall Islands</option> <option value="114">Mauritania</option> <option value="115">Mauritius</option> <option value="116">Mayotte</option> <option value="117">Mexico</option> <option value="118">Micronesia</option> <option value="119">Moldova</option> <option value="120">Monaco</option> <option value="121">Mongolia</option> <option value="208">Montenegro</option> <option value="122">Montserrat</option> <option value="123">Morocco</option> <option value="124">Mozambique</option> <option value="125">Myanmar</option> <option value="126">Namibia</option> <option value="127">Nauru</option> <option value="128">Nepal</option> <option value="129">Netherlands</option> <option value="218">New Caledonia</option> <option value="130">New Zealand</option> <option value="131">Nicaragua</option> <option value="132">Niger</option> <option value="133">Nigeria</option> <option value="134">Niue</option> <option value="135">Norfolk Island</option> <option value="136">North Korea</option> <option value="225">Northern Cyprus</option> <option value="137">Norway</option> <option value="138">Oman</option> <option value="139">Pakistan</option> <option value="140">Palau</option> <option value="220">Palestine</option> <option value="141">Panama</option> <option value="142">Papua New Guinea</option> <option value="143">Paraguay</option> <option value="144">Peru</option> <option value="145">Philippines</option> <option value="146">Pitcairn Island</option> <option value="147">Poland</option> <option value="148">Portugal</option> <option value="149">Puerto Rico</option> <option value="150">Qatar</option> <option value="214">Rep. of Congo</option> <option value="151">Reunion</option> <option value="152">Romania</option> <option value="153">Russia</option> <option value="154">Rwanda</option> <option value="155">Saint Helena</option> <option value="156">Saint Lucia</option> <option value="157">Samoa</option> <option value="158">San Marino</option> <option value="159">Saudi Arabia</option> <option value="160">Senegal</option> <option value="200">Serbia</option> <option value="161">Seychelles</option> <option value="162">Sierra Leone</option> <option value="163">Singapore</option> <option value="164">Slovakia</option> <option value="165">Slovenia</option> <option value="217">Solomon Islands</option> <option value="166">Somalia</option> <option value="224">Somaliland</option> <option value="202">South Africa</option> <option value="167">South Korea</option> <option value="219">South Sudan</option> <option value="168">Spain</option> <option value="169">Sri Lanka</option> <option value="170">Sudan</option> <option value="171">Suriname</option> <option value="172">Swaziland</option> <option value="173">Sweden</option> <option value="174">Switzerland</option> <option value="175">Syria</option> <option value="176">Taiwan</option> <option value="177">Tajikistan</option> <option value="178">Tanzania</option> <option value="179">Thailand</option> <option value="180">Togo</option> <option value="181">Tokelau</option> <option value="182">Tonga</option> <option value="216">Trinidad and Tobago</option> <option value="183">Tunisia</option> <option value="184">Turkey</option> <option value="185">Turkmenistan</option> <option value="186">Tuvalu</option> <option value="187">Uganda</option> <option value="188">Ukraine</option> <option value="201">United Arab Emirates</option> <option value="189">United Kingdom</option> <option value="190">United States</option> <option value="191">Uruguay</option> <option value="192">Uzbekistan</option> <option value="193">Vanuatu</option> <option value="194">Venezuela</option> <option value="195">Vietnam</option> <option value="196">Virgin Islands</option> <option value="223">Western Sahara</option> <option value="197">Yemen</option> <option value="198">Zambia</option> <option value="199">Zimbabwe</option> </select><br><br> Team(s) unit changes to monitor <input type="checkbox" id="axisCheck">Axis <input type="checkbox" id="alliesCheck">Allies<br><br> Max Notification Frequency <input type="text" id="notifCD"> Minutes<br> <p>*Note: You will get notification immediately after a unit count change, this is a 'cooldown' to prevent notification spam if lots of changes occur quickly. </p> <br><a><button id="saveSettingsButton" class="btn_stl">Save and Close</button></a><br><br> </div> `