naz7 / Grepolis Incognito Messages

// ==UserScript==
// @name         Grepolis Incognito Messages
// @namespace    Naz
// @version      0.1.2
// @description  Read messages without them appearing as read
// @author       naz
// @updateURL    https://openuserjs.org/meta/naz7/Grepolis_Incognito_Messages.meta.js
// @downloadURL  https://openuserjs.org/src/scripts/naz7/Grepolis_Incognito_Messages.user.js
// @include      http://*.grepolis.com/game/*
// @include      https://*.grepolis.com/game/*
// @exclude      view-source://*
// @exclude      https://classic.grepolis.com/game/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const translations = {
        "en": {
            INCOGNITO: "Incognito",
            NO_GUEST_RECIPIENT: "No guest player found, find someone to forward the message",
            DEFAULT_FWD_MSG_CONTENT: "This message will be forwarded to a inactive (very likely) guest or to the chosen player(s).\nWhen sent, you will be able to read the sent message with the content of the one that you didn't want to be marked as read.\nIt's recommended to remove this text and write your own, althought this will be invisible, but not impossible to detect."
        },
        "es": {
            INCOGNITO: "Incognito",
            NO_GUEST_RECIPIENT: "No se encontraron guests, busca a alguien a quien reenviar el mensaje",
            DEFAULT_FWD_MSG_CONTENT: "Este mensaje será reenviado a un guest inactivo (muy probablemente) o a el/los jugador/es que indiques.\nCuando lo envíes podrás leer tu mensaje enviado con el contenido del mensaje que no querías que se marque como leído.\nSe recomienda que borres este texto y escribas el tuyo, aunque este será invisible, pero no imposible de detectar."
        }
    };

    const guestNames = [];
    //const alreadyWorkedIDs = [];
    const lang = Game.locale_lang.substring(0, 2);
    const head = document.getElementsByTagName('head')[0];

    let openingIncognitoMessage = false;

    // -- BEGIN Utils
    function addStyle(css) {
        if (!head) { return; }
        var style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        head.insertBefore(style, head.firstChild);
    }

    function getTranslation(s) {
        if (translations[lang] && translations[lang][s]) {
            return translations[lang][s];
        } else if (translations["en"] && translations["en"][s]) {
            return translations["en"][s];
        } else {
            return "Translation not found!";
        }
    }
    // -- END utils

    window.setOpeningIncognitoMessage = function(newState) {
        openingIncognitoMessage = newState;
    };

    addStyle(`
.msg-incognito-btn {
display: inline !important;
padding: 5px 0px !important;
}

.msg-incognito-btn-horizontal-padding {
display: inline !important;
padding: 5px 4px !important;
}
`);

    $.ajax({method:"get", url:"/data/players.txt"}).done(function(content) {
        //console.log("Getting data/players.txt");
        try {
            $.each(content.split(/\r\n|\n/), function(b, line) {
                const parts = line.split(/,/);
                const name = decodeURIComponent(parts[1] + "").replace(/\+/g, " ");
                const allianceId = parts[2];
                const points = parts[3] * 1;

                /**
                 * We want to store guest names to forward them messages and do the trick, because guest ones are never gonna join the game again
                 * in 99% of the times, they're unregistered players playing from the Grepolis App and hardly ever upgrade their guest account to a normal one
                 * With 225 points or less it's probably an inactive player, which is what we want because we don't want those forwarded messages
                 * to be read by anyone else and an inactive player won't
                 * Also it must not have an alliance, as it may be a sign of potential activity in some time
                 *
                 * TODO: also check inactivity
                **/
                if (name.length === 24 && points <= 225 && !allianceId && name.indexOf("guest") == 0) {
                    guestNames.push(name);
                }
            });
            //console.log(guestNames);
        } catch (exception) {
            console.log("Error getting players from data/players.txt: " + exception);
        }
    });

    // Listen to every AJAX request
    $(document).ajaxComplete(function(e, d, l) {
        if ("undefined" != typeof l && "undefined" != typeof d) {
            e = l.url.replace(/\/game\/(.*)\?.*/, "$1");
            //console.log("API call: " + e);
            if ("message" === e) {
                $.each(Layout.wnd.getAllOpen(), function(a, d) {
                    var c = "frontend_bridge" != e ? e : (-1 < l.url.indexOf("json") ? JSON.parse(unescape(l.url).split("&")[3].split("=")[1]).window_type : e);
                    if ("frontend_bridge" != e) {
                        c = Layout.wnd.GetByID(d.getID());
                        if ("message" === c.getController()/* && alreadyWorkedIDs.indexOf(c.getID()) === -1*/) {
                            const ctx = c.getContext().sub;
                            //console.log("Messages Window ID: " + c.getID());
                            //console.log(ctx);

                            if ("message_index" === ctx) {
                                const msgWndElem = c.getJQElement();

                                //console.log("Messages IDs:");
                                $(msgWndElem).find(".message_item").each(function(){
                                    const regex = /'messageView', *(.*), *'view'/;
                                    const match = regex.exec($(this).html());
                                    const msgId = match[1];
                                    //console.log(msgId);

                                    const msgDate = $(this).find(".message_date")[0];
                                    if ($(msgDate).find("a.button > span.msg-incognito-btn").length === 0) {
                                        $(msgDate).append(`
<a class="button" onclick="setOpeningIncognitoMessage(true); w(this).sendMessage('messageForward', ${msgId});" href="#">
<span class="left msg-incognito-btn">
<span class="right msg-incognito-btn">
<span class="middle msg-incognito-btn-horizontal-padding">${getTranslation("INCOGNITO")}</span>
<span style="clear:both;"></span>
</span>
</span>
</a>
`);
                                    }

                                });
                            } else if ("message_forward" === ctx && openingIncognitoMessage) {
                                if (guestNames) {
                                    $("#message_recipients").val(guestNames[~~(guestNames.length * Math.random())]);
                                } else {
                                    $("#message_recipients").val(getTranslation("NO_GUEST_RECIPIENT"));
                                }
                                openingIncognitoMessage = false;
                                $("#message_message").val(`[size=1][color=#ffebbd][i]
${getTranslation("DEFAULT_FWD_MSG_CONTENT")}
[/i][/color][/size]`);
                            }

                            //alreadyWorkedIDs.push(c.getID());
                        }
                    }
                });
            }
        }
    });
})();