// ==UserScript==
// @name FMES by Taznister
// @namespace http://tampermonkey.net/
// @version 0.0.3
// @license MIT
// @description Faction Members Extended Status. Displays extended information in column Status in Faction members page
// @author Taznister [3770016]
// @match https://www.torn.com/factions.php?step=profile&ID=*
// @match https://www.torn.com/factions.php?step=profile&userID=3770016
// @match https://www.torn.com/factions.php?step=your*
// @match https://www.torn.com/preferences.php*
// @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @grant none
// ==/UserScript==
(function() {
'use strict';
const factionId = getUrlParameterByName("ID");
const travelArrow = {
"standard": {
"to": "→", // → single right
"from": "←" // ← single left
},
"airstrip": {
"to": "⇒", // ⇒ right double
"from": "⇐" // ⇐ left double
},
"private": {
"to": "⇛", // ⇛ triple right
"from": "⇚" // ⇚ triple left
},
"business": {
"to": "⥤", // ⥤ harpoon right
"from": "⥢" // ⥢ harpoon left
}
}
const travelStatus = {
"Traveling to Argentina": "Arg",
"Returning to Torn from Argentina": "Arg",
"Traveling to Canada": "Can",
"Returning to Torn from Canada": "Can",
"Traveling to Cayman Islands": "CI",
"Returning to Torn from Cayman Islands": "CI",
"Traveling to China": "China",
"Returning to Torn from China": "China",
"Traveling to Hawaii": "Hawaii",
"Returning to Torn from Hawaii": "Hawaii",
"Traveling to Japan": "Japan",
"Returning to Torn from Japan": "Japan",
"Traveling to Mexico": "Mex",
"Returning to Torn from Mexico": "Mex",
"Traveling to South Africa": "SA",
"Returning to Torn from South Africa": "SA",
"Traveling to Switzerland": "Switz",
"Returning to Torn from Switzerland": "Switz",
"Traveling to UAE": "UAE",
"Returning to Torn from UAE": "UAE",
"Traveling to United Kingdom": "UK",
"Returning to Torn from United Kingdom": "UK",
}
const abroadStatus = {
"In Argentina": "Arg",
"In Canada": "Canada",
"In Cayman Islands": "CI",
"In China": "China",
"In Hawaii": "Hawaii",
"In Japan": "Jap",
"In Mexico": "Mex",
"In South Africa": "SA",
"In Switzerland": "Switz",
"In UAE": "UAE",
"In United Kingdom": "UK",
}
const hospWhere = {
"In hospital for ": " ",
"In an Argentinia": "Ar ",
"In a Canadian ho": "Ca ",
"In a Caymanian h": "Ca ",
"In a Chinese hos": "Ch ",
"In a Hawaiian ho": "Ha ",
"In a Japanese ho": "Ja ",
"In a Mexican hos": "Me ",
"In a South Afric": "SA ",
"In a Swiss hospi": "Sw ",
"In an Emirati ho": "UA ",
"In a British hos": "UK ",
}
let somethingWrong = false;
if (localStorage.getItem("fmes.frequency") === null) localStorage.setItem("fmes.frequency", 10);
if (localStorage.getItem("fmes.userAPIkey") === null) localStorage.setItem("fmes.userAPIkey", "");
let updateFrequency = validateFrequency(localStorage.getItem("fmes.frequency"));
let tornAPIKeyPublic = validateKey(localStorage.getItem("fmes.userAPIkey"));
if (window.location.href.includes("preferences.php")) {
var style = document.createElement("style");
style.innerHTML = "div#fmes-settings {display: block; color: gray; padding: 0.5em; margin: 0.5em 0; border: 1px solid gray;}";
style.innerHTML += "div#fmes-settings input[type='text'], div#fmes-settings input[type='button'] {padding: 0.2em; margin: 0.2em;}";
style.innerHTML += "div#fmes-settings input[type='button']:hover {background-color: gray;}";
document.head.append(style);
const settingsPort = document.querySelector(".content-wrapper");
let settingsDiv = document.createElement("div"); settingsDiv.setAttribute("id", "fmes-settings");
let ul = document.createElement('ul'); ul.innerHTML = "<b>FMES settings:</b>";
let liKey = document.createElement('li');
liKey.innerHTML = "<label>Torn API Key (Public) for FMES: <input type='text' id='fmes-key' value='" + tornAPIKeyPublic + "' /></label>";
let btnValidateKey = document.createElement('input'); btnValidateKey.setAttribute("type", "button"); btnValidateKey.setAttribute("value", "Validate key");
btnValidateKey.addEventListener("click", () => {
let keyInput = document.querySelector("#fmes-key");
tornAPIKeyPublic = validateKey(keyInput.value);
localStorage.setItem("fmes.userAPIkey", tornAPIKeyPublic);
keyInput.value = tornAPIKeyPublic;
});
liKey.appendChild(btnValidateKey);
let liFrequency = document.createElement('li');
liFrequency.innerHTML = "<label>Frequency of status updates [once every <i>x</i> seconds]: <input type='text' id='fmes-frequency' value='" + updateFrequency + "' /></label>";
let btnValidateFrequency = document.createElement('input'); btnValidateFrequency.setAttribute("type", "button"); btnValidateFrequency.setAttribute("value", "Validate frequency");
btnValidateFrequency.addEventListener("click", () => {
let freqInput = document.querySelector("#fmes-frequency");
updateFrequency = validateFrequency(freqInput.value);
localStorage.setItem("fmes.frequency", updateFrequency);
freqInput.value = updateFrequency;
});
let liInfo = document.createElement('span');
liInfo.innerHTML = " (10 is quite safe - it should not interfere with other scripts if you're using them [<a href='https://wiki.torn.com/wiki/API#Automatic_limits_.26_blocks'>more info in Torn wiki</a>])";
liFrequency.appendChild(btnValidateFrequency);
liFrequency.appendChild(liInfo);
ul.appendChild(liKey); ul.appendChild(liFrequency); settingsDiv.appendChild(ul); settingsPort.appendChild(settingsDiv);
}
function validateFrequency(frequency) {
let convertedNumber = parseInt(frequency, 10);
return !isNaN(convertedNumber) && convertedNumber > 0 && Number.isInteger(convertedNumber) ? convertedNumber : 10;
}
function validateKey(key) {
let regex = /^[A-Za-z0-9]{16}$/;
return regex.test(key) ? key : "";
}
function getUrlParameterByName(name, url = window.location.href) {
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
function formatDuration(seconds) {
if (seconds > 60 * 60 * 3) return ">3 h";
else return Math.floor(seconds / 60) + ":" + (seconds % 60).toString().padStart(2, "0");
}
function main() {
if (somethingWrong) return;
let start = performance.now();
fetch("https://api.torn.com/faction/" + factionId + "?selections=basic&key=" + localStorage.getItem("fmes.userAPIkey"))
.then((response) => response.json())
.then((factionData) => {
if (factionData.error != null) {
somethingWrong = true;
} else {
let end = performance.now();
let responseTime = end - start;
let members = factionData.members;
for (let member in members) {
let memberStatusField = document.querySelector('li.table-row:has(a[href$="' + member + '"]) div.table-cell.status span.ellipsis');
if (memberStatusField === null) return;
let forSeconds = members[member].status.until - Math.round((Date.now() + responseTime) / 1000);
if (members[member].status.state == "Traveling") {
let direction = members[member].status.description.includes("Traveling to") ? travelArrow[members[member].status.travel_type].to : travelArrow[members[member].status.travel_type].from;
memberStatusField.innerHTML = direction + " " + travelStatus[members[member].status.description];
} else if (members[member].status.state == "Hospital") {
memberStatusField.innerHTML = hospWhere[members[member].status.description.substring(0, 16)] + formatDuration(forSeconds);
} else if (members[member].status.state == "Abroad") {
memberStatusField.innerHTML = abroadStatus[members[member].status.description];
} else if (members[member].status.state == "Jail") {
memberStatusField.innerHTML = "# " + formatDuration(forSeconds);
} else {
memberStatusField.innerHTML = members[member].status.description;
}
}
}
}
);
}
if (!window.location.href.includes("preferences.php")) {
setTimeout(function() {main()}, 2000);
setInterval(main, updateFrequency * 1000);
}
})();