HALO

Faction armory drug logs in a floating, collapsible panel with correct timestamps and last 20 drug logs, starts minimized

// ==UserScript==
// @name         HALO 
// @namespace    http://tampermonkey.net/
// @version      1.3.8
// @description  Faction armory drug logs in a floating, collapsible panel with correct timestamps and last 20 drug logs, starts minimized
// @author       Nova
// @match        https://www.torn.com/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function() {
    'use strict';

    // Styles
    GM_addStyle(`
      #armoryPanel {
        position: fixed;
        bottom: 0;
        right: 0;
        width: 25%;
        height: 60%;
        background: white;
        color: #000;
        font-family: monospace;
        font-size: 12px;
        border: 1px solid #444;
        border-radius: 8px 8px 0 0;
        overflow-y: auto;
        padding: 10px;
        z-index: 9999;
        transition: all 0.3s ease;
        display: none; /* Start minimized */
      }
      #armoryHeader {
        display: flex;
        justify-content: space-between;
        align-items: center;
        cursor: pointer;
      }
      #armoryLog { margin-top: 5px; }
      .armoryItem { list-style:none; padding:2px 0; }
      .user {color:black; font-weight:bold; margin-right:3px;}
      .drug {color:purple;}
      #bubbleBtn {
        position: fixed;
        bottom: 20px;
        right: 20px;
        background:#222;
        color:#fff;
        border:1px solid #555;
        border-radius:50%;
        width:36px;
        height:36px;
        font-size:18px;
        cursor:pointer;
        display:flex;
        justify-content:center;
        align-items:center;
        z-index:10000;
      }
    `);

    // Panel
    const panel = document.createElement("div");
    panel.id = "armoryPanel";
    panel.innerHTML = `
      <div id="armoryHeader">Faction Drugs Log</div>
      <div id="armoryLog">Loading...</div>
    `;
    document.body.appendChild(panel);

    // Bubble button
    const bubble = document.createElement("div");
    bubble.id = "bubbleBtn";
    bubble.textContent = "💊";
    document.body.appendChild(bubble);

    let minimized = true; // starts minimized
    function togglePanel() {
        minimized = !minimized;
        panel.style.display = minimized ? "none" : "block";
    }
    bubble.addEventListener("click", togglePanel);

    // API key
    let factionKey = GM_getValue("factionAPIKey", null);
    const factionId = "41990"; // your faction ID

    function askKey() {
        let key = prompt("Enter your Faction (Armory) API Key:", factionKey || "");
        if (key) {
            GM_setValue("factionAPIKey", key);
            factionKey = key;
            loadLogs();
        }
    }

    panel.addEventListener("click", () => {
        if (!factionKey) askKey();
    });

    // Fetch logs
    async function loadLogs() {
        if (!factionKey) {
            document.getElementById("armoryLog").innerHTML = "No API key set. Click panel to set.";
            return;
        }
        try {
            let url = `https://api.torn.com/faction/${factionId}?selections=armorynews&key=${factionKey}`;
            let res = await fetch(url);
            let data = await res.json();
            if (data.error) {
                document.getElementById("armoryLog").innerHTML = "Error: " + data.error.error;
                return;
            }

            const logs = data.armorynews;
            if (!logs) {
                document.getElementById("armoryLog").innerHTML = "No drug activity.";
                return;
            }

            // Collect only drug logs first
            const drugLogs = [];
            Object.values(logs).forEach(entry => {
                const text = entry.news;
                const drugMatch = text.match(/(.+) used (one of the faction's )?(.+) items/i);
                if (drugMatch) {
                    const user = drugMatch[1];
                    const drugName = drugMatch[3];
                    // Convert timestamp to armory-style string
                    const date = new Date(entry.timestamp * 1000);
                    const hours = String(date.getHours()).padStart(2,'0');
                    const minutes = String(date.getMinutes()).padStart(2,'0');
                    const day = String(date.getDate()).padStart(2,'0');
                    const month = String(date.getMonth()+1).padStart(2,'0');
                    const year = date.getFullYear();
                    const time = `${hours}:${minutes} ${day}/${month}/${year}`;
                    drugLogs.push({user, drugName, time, timestamp: entry.timestamp});
                }
            });

            // Sort descending by timestamp and get last 20
            drugLogs.sort((a,b)=> b.timestamp - a.timestamp);
            const last20 = drugLogs.slice(0,20);

            let html = "<ul>";
            last20.forEach(entry => {
                html += `<li class="armoryItem">
                            <span class="user">${entry.user}</span> used 
                            <span class="drug">${entry.drugName}</span> at [${entry.time}]
                         </li>`;
            });
            html += "</ul>";
            document.getElementById("armoryLog").innerHTML = html || "No drug activity.";
        } catch (e) {
            document.getElementById("armoryLog").innerHTML = "Request failed.";
        }
    }

    // Auto-refresh
    setInterval(() => {
        if (!minimized && factionKey) loadLogs();
    }, 45000);

    // Initial load
    if (factionKey) loadLogs();

})();