// ==UserScript==
// @name Torn Crimes Burglary Extended
// @namespace https://github.com/SOLiNARY
// @version 0.1
// @description Sorts all scouted by target, confidence, status or uniques number. Remembers your choice.
// @author Ramin Quluzade, Silmaril [2665762]
// @license MIT License
// @match https://www.torn.com/loader.php?sid=crimes*
// @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
// TornPDA support for GM_addStyle
let GM_addStyle = function (s) {
let style = document.createElement("style");
style.type = "text/css";
style.innerHTML = s;
document.head.appendChild(style);
};
GM_addStyle(`
div.silmaril-crimes-burglary-header > div.sections___tZPkg {
height: 25px;
}
div.silmaril-crimes-burglary-header > div.sections___tZPkg > div.silmaril-crimes-burglary-sorting {
cursor: pointer;
}
div.silmaril-crimes-burglary-header > div.sections___tZPkg > div.crimeOptionImage___o2cmT {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
height: 25px;
}
div.silmaril-crimes-burglary-sorting-status {
width: 75px;
}
div.silmaril-crimes-burglary-sorting-has-uniques {
width: 34px;
}
@media only screen and (max-width: 784px) {
div.silmaril-crimes-burglary-sorting-status {
width: 55px;
}
div.silmaril-crimes-burglary-sorting-has-uniques {
width: 55px;
}
}
`);
const sortBy = {
"Target": 10,
"Confidence": 20,
"Status": 30,
"HasUniques": 40
};
const sortDirection = {
"Ascending": 1,
"Descending": -1
}
let currentSortBy = localStorage.getItem("silmaril-torn-crimes-burglary-sorting-by") ?? sortBy.Target;
currentSortBy = parseInt(currentSortBy);
let currentSortDirection = localStorage.getItem("silmaril-torn-crimes-burglary-sorting-direction") ?? sortDirection.Descending;
currentSortDirection = parseInt(currentSortDirection);
const targetNode = document.querySelector("div.crimes-app");
const config = { childList: true, subtree: true };
const observer = new MutationObserver((mutationsList, observer) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList' && mutation.target.className == 'crime-root burglary-root') {
$("div.currentCrime___KNKYQ").on("click", "div.topSection___HchKK div.crimeBanner___LiKtj div.crimeSliderArrowButtons___N_y4N button.arrowButton___gYTVW", function(){
observer.observe(targetNode, config);
});
$("div.currentCrime___KNKYQ").on("click", "div.crimeOptionGroup___gQ6rI:not(.firstGroup___y692r) div.silmaril-crimes-burglary-sorting", function(event){
let sortName = event.target.getAttribute("data-sort-name");
let newSortBy = sortBy[sortName];
let newSortDirection = newSortBy === currentSortBy ? currentSortDirection * -1 : currentSortDirection;
sortChildElements(mutation.target, newSortBy, newSortDirection);
currentSortBy = newSortBy;
currentSortDirection = newSortDirection;
localStorage.setItem("silmaril-torn-crimes-burglary-sorting-by", newSortBy);
localStorage.setItem("silmaril-torn-crimes-burglary-sorting-direction", newSortDirection);
});
console.log("target:", mutation.target);
addHeader(mutation.target);
sortChildElements(mutation.target, currentSortBy, currentSortDirection);
observer.disconnect();
break;
}
}
});
observer.observe(targetNode, config);
// Function to sort child elements
function sortChildElements(element, sortByProperty, sortDirection) {
const parentElement = element.querySelector('.crimeOptionGroup___gQ6rI:not(.firstGroup___y692r)');
const childElements = Array.from(parentElement.querySelectorAll('.crimeOption___LP90y:not(.silmaril-crimes-burglary-header)'));
let targetStats = {};
// Sort properties based on the filter
switch (sortByProperty){
case sortBy.Target:
childElements.sort((a, b) => {
const aValue = a.querySelector('div.sections___tZPkg > .crimeOptionSection___hslpu').textContent;
const bValue = b.querySelector('div.sections___tZPkg > .crimeOptionSection___hslpu').textContent;
return aValue.localeCompare(bValue) * sortDirection;
});
break;
case sortBy.Confidence:
childElements.sort((a, b) => {
const aValue = a.querySelectorAll('div.sections___tZPkg > .crimeOptionSection___hslpu')[1].querySelector('.progressFill___CcY9V').style.height.slice(0, -1);
const bValue = b.querySelectorAll('div.sections___tZPkg > .crimeOptionSection___hslpu')[1].querySelector('.progressFill___CcY9V').style.height.slice(0, -1);
return aValue.localeCompare(bValue, undefined, {'numeric': true}) * sortDirection;
});
break;
case sortBy.Status:
childElements.sort((a, b) => {
const aValue = a.querySelectorAll('div.sections___tZPkg > .crimeOptionSection___hslpu')[1].querySelector('.safetyStatusIcon___SvI0l').style.backgroundPositionY.slice(0, -2);
const bValue = b.querySelectorAll('div.sections___tZPkg > .crimeOptionSection___hslpu')[1].querySelector('.safetyStatusIcon___SvI0l').style.backgroundPositionY.slice(0, -2);
return aValue.localeCompare(bValue, undefined, {'numeric': true}) * sortDirection;
});
break;
case sortBy.HasUniques:
childElements.sort((a, b) => {
const aValue = a.querySelectorAll('div.sections___tZPkg > .crimeOptionSection___hslpu.commitButtonSection___wJfnI div.uniqueStar___QV66l').length;
const bValue = b.querySelectorAll('div.sections___tZPkg > .crimeOptionSection___hslpu.commitButtonSection___wJfnI div.uniqueStar___QV66l').length;
return (aValue < bValue ? -1 : aValue > bValue ? 1 : 0) * sortDirection;
});
break;
default:
console.error("[TornCrimesBurglaryExtended] Unexpected sort values!", sortByProperty, sortDirection);
break;
}
parentElement.append(...childElements);
let targetsDropdown = document.querySelector('div.locationSelectSection___tuGuW ul');
}
function addHeader(element) {
const parentElement = element.querySelector('.crimeOptionGroup___gQ6rI:not(.firstGroup___y692r)');
if (parentElement.querySelector('.crimeOption___LP90y') == null){
return;
}
let headerOuterDiv = document.createElement('div');
headerOuterDiv.className = 'crimeOption___LP90y crime___tIT_g silmaril-crimes-burglary-header';
let headerInnerDiv = document.createElement('div');
headerInnerDiv.className = 'sections___tZPkg';
let delimiter = document.createElement('div');
delimiter.className = 'sectionDelimiter___NpsSC';
let sortByDiv = document.createElement('div');
sortByDiv.className = 'crimeOptionImage___o2cmT';
sortByDiv.textContent = 'Sort by';
let targetDiv = document.createElement('div');
targetDiv.className = 'crimeOptionSection___hslpu flexGrow___S5IUQ silmaril-crimes-burglary-sorting silmaril-crimes-burglary-sorting-target';
targetDiv.setAttribute('data-sort-name', 'Target');
targetDiv.textContent = 'Target ⇧⇩';
headerInnerDiv.append(sortByDiv, targetDiv, delimiter.cloneNode());
let confidenceDiv = document.createElement('div');
confidenceDiv.className = 'crimeOptionSection___hslpu flexGrow___S5IUQ silmaril-crimes-burglary-sorting silmaril-crimes-burglary-sorting-confidence';
confidenceDiv.setAttribute('data-sort-name', 'Confidence');
confidenceDiv.textContent = 'Confidence ⇧⇩';
headerInnerDiv.append(confidenceDiv, delimiter.cloneNode());
let statusDiv = document.createElement('div');
statusDiv.className = 'crimeOptionSection___hslpu flexGrow___S5IUQ silmaril-crimes-burglary-sorting silmaril-crimes-burglary-sorting-status';
statusDiv.setAttribute('data-sort-name', 'Status');
statusDiv.textContent = 'Status ⇧⇩';
headerInnerDiv.append(statusDiv, delimiter.cloneNode());
let hasUniquesDiv = document.createElement('div');
hasUniquesDiv.className = 'crimeOptionSection___hslpu flexGrow___S5IUQ silmaril-crimes-burglary-sorting silmaril-crimes-burglary-sorting-has-uniques';
hasUniquesDiv.setAttribute('data-sort-name', 'HasUniques');
hasUniquesDiv.textContent = 'Uniques ⇧⇩';
headerInnerDiv.append(hasUniquesDiv, delimiter.cloneNode());
headerOuterDiv.appendChild(headerInnerDiv);
parentElement.appendChild(headerOuterDiv);
}
function calculateTimeRemaining(timestamp) {
const now = Math.floor(Date.now() / 1000); // Current timestamp in seconds
const timeRemaining = timestamp - now; // Time remaining in seconds
if (timeRemaining <= 0) {
return "Expired";
}
const days = Math.floor(timeRemaining / 86400); // 86400 seconds in a day
const hours = Math.floor((timeRemaining % 86400) / 3600); // 3600 seconds in an hour
const minutes = Math.floor((timeRemaining % 3600) / 60); // 60 seconds in a minute
const seconds = timeRemaining % 60;
let remainingTime = "Expires in ";
if (days > 0) {
remainingTime += `${days} day${days === 1 ? '' : 's'}, `;
}
if (hours > 0) {
remainingTime += `${hours} hour${hours === 1 ? '' : 's'}, `;
}
if (minutes > 0) {
remainingTime += `${minutes} minute${minutes === 1 ? '' : 's'}, `;
}
if (seconds > 0) {
remainingTime += `${seconds} second${seconds === 1 ? '' : 's'}`;
}
return remainingTime;
}
})();