Game Chat Exporter

Exports the selected gamechat tab to text

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Game Chat Exporter
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Exports the selected gamechat tab to text
// @author       JK_3
// @match        https://www.warzone.com/MultiPlayer?GameID=*
// @icon         https://icons.duckduckgo.com/ip2/warzone.com.ico
// @grant        none
// @run-at       context-menu
// ==/UserScript==

(function() {
    "use strict";
    // Global vars
    var includeTurnIndicators = true
    var includeTimestamps = false;
    var shortenNames = false;
    var maxNameLength = NaN;

    // Helper functions
    function processChatMessage(message) {
        let text = message.querySelector("[id^=ujs_MessageLabel][id$=_tmp]").innerText;
        let user = message.querySelector("[id^=ujs_PlayerNameLabel][id$=_tmp]").innerText;
        let time = message.querySelector("[id^=ujs_TimestampLabel][id$=_tmp]").innerText;

        let userNameAndTime = "";
        if (user) {
            userNameAndTime += shortenNames ? user.substring(0, maxNameLength) : user;
        }

        if (includeTimestamps) {
            userNameAndTime += " @ " + (new Date(time)).toISOString().replace("T", " ").substring(0, 19);
        }

        if (userNameAndTime.length > 0) {
            userNameAndTime += " : "
        }

        return userNameAndTime + text;
    }

    function processChatTurnSeperator(turnSeperator) {
        let text = turnSeperator.querySelector("[id^=ujs_TurnLabel][id$=_tmp]").innerText;
        let numberOfDashes = Math.round((50 - text.length - 2) / 2);
        let dashes = "-".repeat(numberOfDashes);
        return `${dashes} ${text} ${dashes}`
    }

    // Main function
    function exportSelectedChat() {
        let activeChat = Array.from(document.querySelectorAll(".ujsGameObject[id^=ujs_ChatTab]")).filter(t => t.style.display != "none").at(0)?.querySelector("div[id^=ujs_Content]");

        let output = [];
        for (let message of activeChat.children) {
            if (message.id.includes("ChatMessage")) {
                output.push(processChatMessage(message));
            } else if (includeTurnIndicators && message.id.includes("ChatTurnSeperator")) {
                output.push(processChatTurnSeperator(message));
            }
        }

        return output.join("\n");
    }

    // Create displayable container
    const container = document.createElement("div");
    container.id = "options-panel";

    container.style.position = "absolute";
    container.style.top = "50%";
    container.style.left = "50%";
    container.style.transform = "translateX(-50%) translateY(-50%)";
    container.style.zIndex = "99999"; // Moves element to top of the page

    container.style.background = "white";
    container.style.color = "black";
    container.style.borderRadius = "10px";
    container.style.padding = "1.5rem";
    container.style.textAlign = "left";

    container.innerHTML = `
        <h3 style="margin-top:0;">Chat exporter</h3>
        <p>Exports the selected chat tab to a text field you can copy.</p>

        <div id="includeTurnIndicatorsDiv">
            <label for="includeTurnIndicators">Include turn indicators?</label>
            <input type="checkbox" id="includeTurnIndicators" checked/>
        </div>

        <div id="includeTimestampsDiv">
            <label for="includeTimestamps">Include timestamps?</label>
            <input type="checkbox" id="includeTimestamps"/>
        </div>

        <div id="shortenNamesDiv">
            <label for="shortenNames">Shorten names?</label>
            <input type="checkbox" id="shortenNames"/>
        </div>

        <div id="maxNameLenghtDiv" style="display:none;">
            <label for="maxNameLength">Max name length:</label>
            <input type="number" id="maxNameLength" min="1" value="15" style="width:60px;" />
        </div>

        <div style="margin-bottom:0.8rem;">
            <textarea id="outputText" style="display:none; margin-bottom:0.8rem; height:200px; width:100%" readonly></textarea>
        </div>

        <div style="text-align:center;">
            <button id="runBtn" style="background-color:blue;color:white;border:none;padding:0.5rem 1rem;border-radius:6px;cursor:pointer;">Run</button>
            <button id="closeBtn" style="background-color:lightgray;color:black;border:none;padding:0.5rem 1rem;border-radius:6px;cursor:pointer; margin-left:0.5rem;">Close</button>
        </div>
    `;

    document.body.appendChild(container);

    // Behavior
    const includeTurnIndicatorsCheckBox = container.querySelector("#includeTurnIndicators");
    const includeTimeStampsCheckBox = container.querySelector("#includeTimestamps");
    const shortenNamesCheckbox = container.querySelector("#shortenNames");
    const maxLengthInputDiv = container.querySelector("#maxNameLenghtDiv");
    const runBtn = container.querySelector("#runBtn");
    const closeBtn = container.querySelector("#closeBtn");
    const outputText = container.querySelector("#outputText");

    shortenNamesCheckbox.addEventListener("change", () => {
        maxLengthInputDiv.style.display = shortenNamesCheckbox.checked ? "block" : "none";
    });

    runBtn.addEventListener("click", () => {
        // Update the settings
        includeTurnIndicators = includeTurnIndicatorsCheckBox.checked;
        includeTimestamps = includeTimeStampsCheckBox.checked;
        shortenNames = shortenNamesCheckbox.checked;
        let maxNameLengthText = shortenNames ? container.querySelector("#maxNameLength").value : null;
        maxNameLength = parseInt(maxNameLengthText);
        shortenNames = shortenNames && !isNaN(maxNameLength);

        // Update display
        let result = exportSelectedChat();
        if (result) {
            outputText.value = result;
            outputText.style.color = "black";
        } else {
            outputText.value = "No chats were loaded, either because you didn't select a chat tab to become active or because your selected chat didn't have any messages.";
            outputText.style.color = "red";
        }
        outputText.style.display = "block";
    });

    closeBtn.addEventListener("click", () => {
        container.remove();
    });
})();