// ==UserScript==
// @name TornCAT Faction Player Filters
// @namespace torncat
// @version 1.2.3
// @description This script adds player filters on various pages (see matches below).
// @author Wingmanjd[2127679]
// @match https://www.torn.com/factions.php*
// @match https://www.torn.com/hospitalview.php*
// @match https://www.torn.com/jailview.php*
// @match https://www.torn.com/index.php?page=people*
// @match https://www.torn.com/friendlist.php*
// @match https://www.torn.com/blacklist.php*
// ==/UserScript==
'use strict';
let apikey = '###PDA-APIKEY###';
let tornPdaMode = false;
// Need to check if script is running within TornPDA app.
if (apikey.slice(-1) != '#') {
// Script is running in TornPDA mode.
tornPdaMode = true;
}
// Override the GM_addStyle function so it can be used within TornPDA.
let GM_addStyle = function(s)
{
let style = document.createElement("style");
style.type = "text/css";
style.innerHTML = s;
document.head.appendChild(style);
};
// Class declarations
/************************************** */
class PlayerIDQueue {
constructor() {
this.playerIDs = this.findPlayerIDs();
this.queries = 0;
this.start = new Date();
}
enqueue(el) {
this.playerIDs.push(el);
}
dequeue() {
return this.playerIDs.shift();
}
findPlayerIDs() {
let users = $('.user.name');
let players = users.toArray();
let playerIDs = [];
players.forEach(function(el){
let regex = /(XID=)(\d*)/;
let found = el.href.match(regex);
let playerID = Number(found[0].slice(4));
// Push to new array if not already present.
if (playerIDs.indexOf(playerID) == -1){
playerIDs.push(playerID);
}
});
return playerIDs;
}
isEmpty() {
return this.playerIDs.length == 0;
}
peek() {
return !this.isEmpty() ? this.playerIDs[0] : undefined;
}
length() {
return this.playerIDs.length;
}
requeue() {
let element = this.peek();
this.dequeue();
this.enqueue(element);
}
clear() {
if( !tornPdaMode && develCheck ) console.debug('API Cache Dump:', apiDataCache);
this.playerIDs = [];
}
}
// Global script variables:
/************************************** */
// Development flag.
let develCheck = false;
let localStorageLocation = 'torncat.factionFilters';
// Local cache for api data.
let apiDataCache = {};
var data = data || {};
// Player queue
let queue = new PlayerIDQueue();
// Torn API query limit, to prevent flood protection rejections.
let apiQueryLimit = 60;
// Calculated values of checkboxes;
var reviveCheck = false;
var attackCheck = false;
var offlineCheck = false;
// Main script.
/************************************** */
(function() {
'use strict';
console.log('Faction Player Filters (FPF) started');
// Load localStorage;
loadData();
// Save data back to localStorage;
save();
// Automatically display widget for pages that load user lists via AJAX.
$( document ).ajaxComplete(function( event, xhr, settings ) {
if (hideAjaxUrl(settings.url) == false) {
renderFilterBar();
reapplyFilters();
}
});
// Manually display the filter widget if current url matches an item in the manualList array.
// Following pages don't load the user list via AJAX.
let manualList = [
'page=people',
'step=profile',
'blacklist.php',
'friendlist.php',
'hospitalview.php',
'jailview.php',
'factions.php',
];
manualList.forEach(el =>{
if (window.location.href.match(el)){
renderFilterBar();
}
});
})();
/**
* Load localStorage data.
*/
function loadData(){
data = localStorage.getItem(localStorageLocation);
if(data == null) {
// Default settings
data = {
apiKey : apikey,
apiQueryDelay : 250,
hideFactionDescription: false,
queries: 0,
start: '0'
};
} else {
data = JSON.parse(data);
if (data.apiQueryDelay == undefined){
data.apiQueryDelay = 250;
}
}
// Calculate values of checkboxes.
// eslint-disable-next-line no-undef
reviveCheck = $('#tc-filter-revive').prop('checked');
// eslint-disable-next-line no-undef
attackCheck = $('#tc-filter-attack').prop('checked');
// eslint-disable-next-line no-undef
offlineCheck = $('#tc-filter-offline').prop('checked');
develCheck = $('#tc-devmode').prop('checked');
}
/**
* Save localStorage data.
*/
function save(){
console.log('FPF local data saved');
localStorage.setItem('torncat.factionFilters', JSON.stringify(data));
}
/**
* Renders HTML filter elements above the user list.
*/
function renderFilterBar() {
// Generate HTMl.
let reviveCheck = '#tc-filter-revive';
let attackCheck = '#tc-filter-attack';
let offlineCheck = '#tc-filter-offline';
let refreshCheck = '#tc-refresh';
let widgetLocationsSelector = '';
let widgetHTML = `
`;
let filterBar = $('.torncat-player-filter-bar');
// Only insert if there isn't already a filter bar on the page.
if ($(filterBar).length != 1){
if (window.location.href.match('factions.php')){
widgetLocationsSelector = '#faction-info-members';
} else {
widgetLocationsSelector = '.users-list-title';
}
var widgetLocationsLength = $(widgetLocationsSelector).length;
$(widgetHTML).insertBefore($(widgetLocationsSelector)[widgetLocationsLength - 1]);
// Scroll mobile view.
if ($(window).width() < 1000 && data.hideFactionDescription ) {
setTimeout(() => {
document.querySelector('.torncat-player-filter-bar').scrollIntoView({
behavior: 'smooth'
});
},2000);
}
/* Add event listeners. */
$('.torncat-player-filter-bar a.torncat-icon').click(function () {
$('.api-key-prompt').toggle();
});
// Disable filters on Hospital/ Jail pages.
if (
window.location.href.startsWith('https://www.torn.com/hospital') ||
window.location.href.startsWith('https://www.torn.com/jail')
){
$('#tc-filter-revive').prop('checked', true);
$('#tc-filter-revive').parent().hide();
$('#tc-filter-attack').parent().hide();
}
// Watch for event changes on the revive mode checkbox.
$(reviveCheck).change(() => {
toggleUserRow('revive');
if ($(attackCheck).prop('checked')){
$(attackCheck).prop('checked', false);
toggleUserRow('attack');
}
});
// Watch for event changes on the attack mode checkbox.
$(attackCheck).change(() => {
loadData();
toggleUserRow('attack');
if ($(reviveCheck).prop('checked')){
$(reviveCheck).prop('checked', false);
toggleUserRow('revive');
}
});
// Watch for event changes on the Hide Offline mode checkbox.
$(offlineCheck).change(() => {
loadData();
toggleUserRow('offline');
});
// Watch for event changes on the Auto-refresh checkbox.
$('#tc-refresh').change(() => {
if ($(refreshCheck).prop('checked')) {
console.log('FPF: Starting auto-refresh');
let queue = new PlayerIDQueue();
processRefreshQueue(queue);
} else {
console.log('FPF: Stopped processing queue. Queue cleared');
loadData();
if( !tornPdaMode && develCheck ) console.debug(data);
queue.clear();
}
});
}
if ($('.api-key-prompt').length != 1){
renderSettings();
}
}
/**
* Renders API key and other filter settings.
*/
function renderSettings(forceCheck) {
// Generate HTMl.
let saveAPIKeyButton = '';
let hideFactionDescription = ' Hide Faction Description
';
let devButton = ' Devel Mode
';
let clearAPIKeyButton = '
';
let input = '
';
let delayOption = '';
delayOption += ' ';
let block = '
';
block += '
TornCAT - Player Filters
';
block += '
';
block += '
Click the black icon in the filter row above to toggle this pane.
';
if (!tornPdaMode) {
block += '
Auto Refresh requires a Torn API key. It will never be transmitted anywhere outside of Torn