Torn Crimes Burglary Extended

Sorts all scouted by target, confidence, status or uniques number. Remembers your choice.

目前为 2023-09-16 提交的版本。查看 最新版本

// ==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;
    }
})();