torn-attack-hospital-timer

Display hospital timer on the attack page

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name        torn-attack-hospital-timer
// @namespace   typhon.torn.attack-hospital
// @version     1.5.3
// @description Display hospital timer on the attack page
// @author      rantMore [3265877]
// @license     GNU GPLv3
// @run-at      document-end
// @license     MIT
// @grant       GM_log
// @grant       GM_addStyle
// @match       https://www.torn.com/loader.php?sid=attack*
// @match       https://www.torn.com/page.php?sid=attack*
// ==/UserScript==

const apiKey = "YOUR_API_KEY_HERE";

// ## DO NOT EDIT FROM THIS POINT ON ##
const TAHT_VERSION = '1.5.3';
const divContainer = '.dialog___Q0GdI';
const divTopSection = '.topSection___U7sVi';
const initialTitle = document.title;
const userid = location.href.replace(/.*?user2ID=(\d+)/i, "$1");
let userFactionid = 0;
let factionInformation = {};
let userInformation = {};

let singleton = document.getElementById("taht-scouter-run-once");
if (!singleton) {
  console.log(`[Torn Attack Hospital Timer] Version ${TAHT_VERSION} starting`);
  GM_addStyle(`
     .timer-indicator {
        padding: 10px 10px;
        background-color: #000000;
        font-weight: 700;
        font-size: 1.2rem;
        text-align: center;
        color: var(--attack-dialog-red-title)
     }
     .topFactionSection {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        gap: 15px;
        justify-content: flex-end;
        font-size: large;
     }
     .info-value-yes {
        color: green;
     }
     .info-value-no {
        color: red;
     }
     `)
}

function generateInformation(outTime, hospital_timestamp) {
    // Show green under 1 minute
    const seconds = Math.floor((outTime - Date.now()) / 1000);
    return `
    <div>&nbsp;</div>
    <div>Coming out at ${outTime.toLocaleTimeString('en-US')} in</div>
    <div class="timer-indicator"><span style="${seconds < 120 ? 'color: #98FB98' : ''}">${getTimeLeft(hospital_timestamp)}</span></div>
    `;
}

function getTimeLeft(hospital_timestamp) {
    let outTime = new Date(0);
    outTime.setUTCSeconds(hospital_timestamp);
    const seconds = Math.floor((outTime - Date.now()) / 1000);
    if (seconds >= 60) {
        const secondsFormated = Math.floor(seconds % 60).toString().padStart(2, '0');
        return seconds < 3600 ? `${Math.floor(seconds/60)}:${secondsFormated}` : `${Math.floor(seconds / 3600)}h${Math.floor((seconds % 3600) / 60).toString().padStart(2, '0')}`;
    } else {
        return `${seconds}s`;
    }
}

function fetch_FactionInfo() {
    return new Promise( (resolve, reject) => {
        if (userFactionid) {
            fetch(`https://api.torn.com/faction/${userFactionid}/wars?key=${apiKey}&comment=attack_stats`).then( async response => {
                factionInformation = (await response.json())||{};
                resolve(factionInformation);
            })
        } else {
            resolve(undefined);
        }
    });
}

function fetch_UserInfo() {
    return new Promise( (resolve, reject) => {
        if (userFactionid) {
            fetch(`https://api.torn.com/user/${userid}?selections=profile&key=${apiKey}&comment=attack_stats`).then( async response => {
                userInformation = (await response.json())||{};
                updateUserInfo();
                resolve(userInformation);
            })
        } else {
            resolve(undefined);
        }
    });
}

function updateUserInfo() {
    if (userInformation) {
        let statusDiv = document.querySelector('.topFactionSection #lastAction-info');
        statusDiv.innerHTML = `Last action: <span class="info-value">${userInformation.last_action.relative}</span>`;
        statusDiv = document.querySelector('.topFactionSection #online-info');
        statusDiv.innerHTML = `Online: <span class="info-value-${ userInformation.last_action.status === 'Online' ? 'yes' : 'no'}">${ userInformation.last_action.status === 'Online' ? 'Yes' : 'No'}</span>`;
    }
}

(function hospital_time() {
    'use strict';

    fetch(`https://api.torn.com/user/${userid}?selections=profile&key=${apiKey}&comment=attack_stats`).then( async response => {
        let user = (await response.json())||{};
        userInformation = user;

        // Grab the top section and add our div
        let outerBox = document.querySelector(divTopSection);
        if (outerBox) {
            let divExtraWrapper = document.createElement("div")
            divExtraWrapper.setAttribute("class", "topFactionSection");
            divExtraWrapper.innerHTML = `
                    <div id="war-info">War: <span class="info-value-no">N/A</span></div>
                    <div id="tt-info">Territory: <span class="info-value-no">N/A</span></div>
                    <div id="lastAction-info">Territory: <span class="info-value-no">N/A</span></div>
                    <div id="online-info">Online: <span class="info-value-no">N/A</span></div>
                    `;
            outerBox.after(divExtraWrapper);
            updateUserInfo();
        }

        // If user is in faction, grab the information
        if (user?.faction) {
            userFactionid = user.faction.faction_id || 0;
            fetch_FactionInfo().then( (faction) => {
                if (faction) {
                    // Grab top section box, we'll add it next to it
                    let outerBox = document.querySelector(divTopSection);
                    if (outerBox) {
                        const wars = Object.entries(faction.ranked_wars||{})[0];
                        const tts = Object.entries(faction.territory_wars||{})[0];
                        const isInWar = wars && wars[0] ? true : false;
                        const isInTT = tts && tts[0] ? true : false;

                        let statusDiv = document.querySelector('.topFactionSection #war-info');
                        if (statusDiv) {
                            statusDiv.innerHTML = `War: <span class="info-value-${ isInWar ? 'yes' : 'no'}">${ isInWar ? 'Yes' : 'No'}</span>`;
                        }
                        statusDiv = document.querySelector('.topFactionSection #tt-info');
                        if (statusDiv) {
                            statusDiv.innerHTML = `Territory: <span class="info-value-${ isInTT ? 'yes' : 'no'}">${ isInTT ? 'Yes' : 'No'}</span>`;
                        }
                    } else {
                        // What to do???
                    }
                } else {
                    // no faction??
                }
            })
        }

        if (user.status.state.toLowerCase() === 'hospital') {
            let alertWrapper = document.createElement("div")
            alertWrapper.setAttribute("class", "userName___loAWK bold");

            let outTime = new Date(0); // The 0 there is the key, which sets the date to the epoch
            outTime.setUTCSeconds(user.states.hospital_timestamp);

            // Don't do anything if we are right on the ending of the hospital timer
            let msToWait = outTime - Date.now();

            // Prepare div content
            alertWrapper.innerHTML = generateInformation(outTime, user.states.hospital_timestamp);
            document.title = `${getTimeLeft(user.states.hospital_timestamp)} | ${user.name}`;

            // Sometimes the element is not yet present, let's wait for it
            let outerBox = document.querySelector(divContainer);
            let timerPtr;
            let tempBox;
            let tempDiv;
            new Promise( (resolve, reject) => {
                if (!outerBox) {
                    // Lets grab the top div to add the time info insde. If it fails, then too bad for the tentative
                    tempBox = document.querySelector('.colored___sN72G');
                    if (tempBox) {
                        tempDiv = tempBox.appendChild(alertWrapper);
                    }
                    let waitPtr = setInterval( () => {
                        document.title = `${getTimeLeft(user.states.hospital_timestamp)} | ${user.name}`;
                        outerBox = document.querySelector(divContainer);
                        if (outerBox) {
                            resolve(true)
                            clearInterval(waitPtr);
                        }
                    }, 250)
                    } else {
                        resolve(true)
                    }
            }).then( () => {
                // Good to go!
                if (tempDiv) {
                    // lets get rid of this extra div
                    tempDiv.remove()
                }
                outerBox.appendChild(alertWrapper);

                // Redraw content every second
                timerPtr = setInterval( () => {
                    alertWrapper.innerHTML = generateInformation(outTime, user.states.hospital_timestamp);
                    document.title = `${getTimeLeft(user.states.hospital_timestamp)} | ${user.name}`;
                }, 1000);

                // Check status periodically
                setInterval( () => {
                    fetch_UserInfo().then( (user) => {
                        //console.log('fetched user', user);
                    });
                }, 5000)
            })

            // Set a new timer to trigger when we are done waiting
            setTimeout( () => {
                // Stop everything, we are done.
                document.title = initialTitle;
                clearInterval(timerPtr);
            }, msToWait);
        }
    });
})();