[Eh] Account Manager

Eh Account Manager - Auto login and switch between multiple accounts, supports shared accounts and import/export cookie, modified from greasyfork.org/scripts/470710

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.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

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         [Eh] Account Manager
// @name:zh-CN   [Eh] 账号管理
// @name:zh-TW   [Eh] 帳號管理
// @name:ja      [Eh] アカウント管理
// @name:ko      [Eh] 계정 관리
// @name:ru      [Eh] Управление аккаунтами
// @name:en      [Eh] Account Manager
// @version      1.0.1
// @author       Li
// @description         Eh Account Manager - Auto login and switch between multiple accounts, supports shared accounts and import/export cookie, modified from greasyfork.org/scripts/470710
// @description:zh-TW   Eh帳號管理 - 自動登入與多帳號切換,支持共享帳號與導入導出cookie,修改自greasyfork.org/scripts/470710
// @description:zh-CN   Eh账号管理 - 自动登入与多账号切换,支持共享账号与导入导出cookie,修改自greasyfork.org/scripts/470710
// @description:ja      Eh アカウント管理 - 自動ログインと複数アカウント切替、共有アカウントとcookieのインポート/エクスポート対応、greasyfork.org/scripts/470710 から改変
// @description:ko      Eh 계정 관리 - 자동 로그인 및 다중 계정 전환, 공유 계정 및 cookie 가져오기/내보내기 지원, greasyfork.org/scripts/470710 에서 수정
// @description:ru      Eh Управление аккаунтами - Автоматический вход и переключение между аккаунтами, поддерживает общие аккаунты и импорт/экспорт cookie, изменено из greasyfork.org/scripts/470710
// @description:en      Eh Account Manager - Auto login and switch between multiple accounts, supports shared accounts and import/export cookie, modified from greasyfork.org/scripts/470710

// @noframes
// @connect      *
// @match        *://e-hentai.org/*
// @match        *://exhentai.org/*
// @icon         https://e-hentai.org/favicon.ico

// @license      MPL-2.0
// @namespace    https://greasyfork.org/users/1069880

// @require      https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.19.0/js/md5.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js

// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_addValueChangeListener

// @run-at       document-start
// ==/UserScript==

// thanks:
// https://greasyfork.org/scripts/470710 (MPL-2.0)(greasyfork.org/users/989635-canaan-hs)

(async () => {
    const MenuIds = new Set();
    const ListenKeys = new Set();
    const LangMap = {
        ko: "Korea", "ko-KR": "Korea",
        ja: "Japan", "ja-JP": "Japan",
        ru: "Russia", "ru-RU": "Russia",
        en: "English", "en-US": "English", "en-GB": "English", "en-AU": "English", "en-CA": "English", "en-NZ": "English", "en-IE": "English", "en-ZA": "English", "en-IN": "English",
        zh: "Simplified", "zh-CN": "Simplified", "zh-SG": "Simplified", "zh-MY": "Simplified",
        "zh-TW": "Traditional", "zh-HK": "Traditional", "zh-MO": "Traditional"
    };
    const Lib = {
        $domain: location.hostname,
        $q: s => document.querySelector(s),
        cookie: v => v == null ? document.cookie : document.cookie = v,
        getV: (k, d) => GM_getValue(k, d) ?? null,
        setV: (k, v) => GM_setValue(k, v),
        getJV: (k, d) => { try { return JSON.parse(GM_getValue(k, d)); } catch { return d; } },
        setJV: (k, v) => GM_setValue(k, JSON.stringify(v)),
        getDate: (fmt = "{year}-{month}-{date} {hour}:{minute}:{second}") => {
            const now = new Date();
            const map = {
                year: now.getFullYear(),
                month: `${now.getMonth() + 1}`.padStart(2, "0"),
                date: `${now.getDate()}`.padStart(2, "0"),
                hour: `${now.getHours()}`.padStart(2, "0"),
                minute: `${now.getMinutes()}`.padStart(2, "0"),
                second: `${now.getSeconds()}`.padStart(2, "0")
            };
            return fmt.replace(/{([^}]+)}/g, (_, k) => map[k] ?? "Error");
        },
        local: (key, opts = {}) => {
            if (opts.value !== undefined) {
                localStorage.setItem(key, JSON.stringify(opts.value));
                return true;
            }
            const raw = localStorage.getItem(key);
            if (raw == null) return opts.error ?? null;
            try { return JSON.parse(raw); } catch { return opts.error ?? null; }
        },
        addStyle: (css, id) => {
            const style = document.createElement("style");
            style.id = id;
            style.textContent = css;
            const mount = () => (document.head || document.documentElement).appendChild(style);
            if (document.head || document.documentElement) mount();
            else window.addEventListener("DOMContentLoaded", mount, { once: true });
        },
        translMatcher: (map, lang = navigator.language) => map[LangMap[lang]] ?? map[LangMap["en-US"]],
        regMenu: (items, { name = "Menu" } = {}) => {
            let index = 1;
            for (const [label, cfg] of Object.entries(items)) {
                const id = `${name}-${index++}`;
                const opts = typeof cfg === "function" ? { func: cfg } : cfg;
                GM_registerMenuCommand(label, () => opts.func(), { id, title: opts.desc, autoClose: opts.close, accessKey: opts.hotkey });
                MenuIds.add(id);
            }
        },
        unMenu: id => {
            if (MenuIds.has(id)) {
                GM_unregisterMenuCommand(id);
                MenuIds.delete(id);
            }
        },
        storeListen: (keys, cb) => {
            keys.forEach(key => {
                if (!ListenKeys.has(key)) {
                    ListenKeys.add(key);
                    GM_addValueChangeListener(key, (k, ov, nv, far) => cb({ key: k, ov, nv, far }));
                }
            });
        }
    };
    const domain = Lib.$domain;
    const {
        Transl
    } = Language();
    (async function ImportStyle() {
        let show_style, button_style, button_hover, toast_style, acc_style;
        if (domain === "e-hentai.org") {
            button_hover = "color: #8f4701;";
            toast_style = "background-color: #5C0D12; color: #fefefe;";
            show_style = "background-color: #fefefe; border: 3px ridge #34353b;";
            acc_style = "color: #5C0D12; background-color: #fefefe; border: 2px solid #B5A4A4;";
            button_style = "color: #5C0D12; border: 2px solid #B5A4A4; background-color: #fefefe;";
        } else if (domain === "exhentai.org") {
            button_hover = "color: #989898;";
            toast_style = "background-color: #fefefe; color: #5C0D12;";
            show_style = "background-color: #34353b; border: 2px ridge #5C0D12;";
            acc_style = "color: #f1f1f1; background-color: #34353b; border: 2px solid #8d8d8d;";
            button_style = "color: #fefefe; border: 2px solid #8d8d8d; background-color: #34353b;";
            Lib.addStyle(`
                body {
                    padding: 2px;
                    color: #f1f1f1;
                    text-align: center;
                    background: #34353b;
                }
            `);
        }
        Lib.addStyle(`
            .toast-container {
                top: 1.5rem;
                right: 1.5rem;
                z-index: 9999;
                position: fixed;
                display: flex;
                flex-direction: column;
                align-items: flex-end;
                gap: 0.5rem;
                pointer-events: none;
            }
            .toast {
                ${toast_style}
                padding: 0.5rem 1rem;
                font-size: 1rem;
                white-space: nowrap;
                border-radius: 2px;
                box-shadow: 0 2px 6px rgba(0,0,0,0.3);
                opacity: 0;
                transform: translateX(1rem);
                transition: opacity 0.25s ease, transform 0.25s ease;
                pointer-events: auto;
            }
            .toast.show {
                opacity: 1;
                transform: translateX(0);
            }
            .modal-background {
                top: 50%;
                left: 50%;
                opacity: 0;
                width: 100%;
                height: 100%;
                z-index: 8888;
                overflow: auto;
                position: fixed;
                transition: opacity 0.25s ease;
                background-color: rgba(0,0,0,0);
                transform: translate(-50%, -50%);
            }
            .acc-modal {
                ${show_style}
                width: 18%;
                overflow: auto;
                margin: 11rem auto;
                border-radius: 4px;
            }
            .acc-select-flex {
                display: flex;
                align-items: center;
                flex-direction: initial;
                justify-content: space-around;
            }
            .acc-button-flex {
                display: flex;
                padding: 0 0 15px 0;
                justify-content: center;
            }
            .acc-select {
                ${acc_style}
                padding: 4px;
                min-width: 10rem;
                margin: 1.1rem 1.4rem 1.5rem 1.4rem;
                font-weight: bold;
                cursor: pointer;
                font-size: 1.2rem;
                text-align: center;
                border-radius: 2px;
            }
            .show-modal {
                ${show_style}
                width: 25%;
                padding: 1.5rem;
                overflow: auto;
                margin: 5rem auto;
                text-align: left;
                border-radius: 4px;
                border-collapse: collapse;
            }
            .modal-button {
                ${button_style}
                top: 0;
                margin: 3% 2%;
                font-size: 14px;
                font-weight: bold;
                border-radius: 2px;
            }
            .modal-button:hover, .modal-button:focus {
                ${button_hover}
                cursor: pointer;
                text-decoration: none;
            }
            .set-modal {
                ${show_style}
                width: 35%;
                padding: 0.3rem;
                overflow: auto;
                text-align: center;
                border-radius: 4px;
                border-collapse: collapse;
                margin: 2% auto 8px auto;
            }
            .set-box {
                display: flex;
                margin: 0.6rem;
                font-weight: bold;
                flex-direction: column;
                align-items: flex-start;
            }
            .set-list {
                width: 95%;
                font-weight: 550;
                font-size: 1.1rem;
                text-align: center;
            }
            hr {
                width: 98%;
                opacity: 0.2;
                border: 1px solid;
                margin-top: 1.3rem;
            }
            label {
                margin: 0.4rem;
                font-size: 0.9rem;
            }
            .current-login {
                text-align: center;
                font-size: 0.95rem;
                opacity: 0.75;
                margin: 0.2rem 0 0.9rem 0;
                padding: 0.35rem;
                border-radius: 2px;
            }
            .account-list {
                margin: 0.6rem;
                text-align: left;
            }
            .account-item {
                display: flex;
                align-items: center;
                padding: 0.6rem 0.5rem;
                gap: 0.6rem;
                flex-wrap: wrap;
                border-bottom: 1px solid rgba(128,128,128,0.15);
            }
            .account-item:last-child {
                border-bottom: none;
            }
            .account-note {
                flex: 1;
                min-width: 100px;
                padding: 4px 8px;
                font-size: 0.95rem;
            }
            .account-action {
                cursor: pointer;
                font-size: 0.9rem;
                padding: 4px 10px;
                white-space: nowrap;
                border: 1px solid;
                background: transparent;
                color: inherit;
            }
            .account-action:hover {
                opacity: 0.7;
            }
            .account-action:disabled {
                opacity: 0.35;
                cursor: default;
            }
            .account-index {
                font-weight: bold;
                font-size: 1rem;
                min-width: 2rem;
            }
            .modal-close {
                position: absolute;
                top: 0.2rem;
                right: 0.6rem;
                font-size: 1.4rem;
                cursor: pointer;
                opacity: 0.4;
                line-height: 1;
                background: none;
                border: none;
                color: inherit;
            }
            .modal-close:hover {
                opacity: 0.8;
            }
            .tab-bar {
                display: flex;
                margin: 0 0.6rem;
                border-bottom: 2px solid rgba(128,128,128,0.3);
            }
            .tab-btn {
                flex: 1;
                padding: 0.5rem;
                cursor: pointer;
                font-size: 1rem;
                font-weight: bold;
                color: inherit;
                opacity: 0.5;
                background: transparent;
                border: none;
                border-bottom: 2px solid transparent;
                margin-bottom: -2px;
            }
            .tab-btn.active {
                opacity: 1;
                border-bottom-color: currentColor;
            }
            .tab-content {
                padding: 0.6rem 0;
            }
            .tab-actions {
                display: flex;
                justify-content: center;
                gap: 0.5rem;
                margin-top: 0.8rem;
                padding-top: 0.8rem;
                border-top: 1px solid rgba(128,128,128,0.2);
            }
        `, "AutoLogin-Style");
    })();
    (async function Main($Cookie, $Shared) {
        const ACCOUNTS_KEY = "E/Ex_Accounts";
        const OLD_KEY = "E/Ex_Cookies";

        function migrateOldData() {
            if (Lib.getJV(ACCOUNTS_KEY)) return;
            const oldCookies = Lib.getJV(OLD_KEY);
            if (oldCookies && Array.isArray(oldCookies) && oldCookies.length > 0) {
                const now = Lib.getDate("{year}-{month}-{date} {hour}:{minute}");
                Lib.setJV(ACCOUNTS_KEY, [{
                    id: Date.now().toString(),
                    note: "",
                    isDefault: true,
                    cookies: oldCookies,
                    createdAt: now,
                    updatedAt: now
                }]);
            }
        }

        function getAccounts() {
            const data = Lib.getJV(ACCOUNTS_KEY);
            if (!data) return [];
            let accounts;
            if (typeof data === "string") {
                try { accounts = JSON.parse(data); } catch (e) { return []; }
            } else {
                accounts = Array.isArray(data) ? data : [];
            }
            if (accounts.length > 0 && !accounts.some(a => a.isDefault)) {
                accounts[0].isDefault = true;
                saveAccounts(accounts);
            }
            return accounts;
        }

        function saveAccounts(accounts) {
            Lib.setJV(ACCOUNTS_KEY, accounts);
        }

        function getDefaultAccount() {
            const accounts = getAccounts();
            return accounts.find(a => a.isDefault) || accounts[0] || null;
        }

        function addAccount(cookies, note) {
            const accounts = getAccounts();
            const now = Lib.getDate("{year}-{month}-{date} {hour}:{minute}");
            accounts.push({
                id: Date.now().toString(),
                note: note || "",
                isDefault: !accounts.some(a => a.isDefault),
                cookies: cookies,
                createdAt: now,
                updatedAt: now
            });
            saveAccounts(accounts);
        }

        function setDefaultAccount(id) {
            const accounts = getAccounts();
            accounts.forEach(a => a.isDefault = a.id === id);
            saveAccounts(accounts);
            return accounts;
        }

        function updateAccountNote(id, note) {
            const accounts = getAccounts();
            const account = accounts.find(a => a.id === id);
            if (account) {
                account.note = note;
                account.updatedAt = Lib.getDate("{year}-{month}-{date} {hour}:{minute}");
                saveAccounts(accounts);
            }
            return accounts;
        }

        function deleteAccount(id) {
            let accounts = getAccounts();
            accounts = accounts.filter(a => a.id !== id);
            saveAccounts(accounts);
            return accounts;
        }

        function updateAccountCookies(id, cookies) {
            const accounts = getAccounts();
            const account = accounts.find(a => a.id === id);
            if (account) {
                account.cookies = cookies;
                account.updatedAt = Lib.getDate("{year}-{month}-{date} {hour}:{minute}");
                saveAccounts(accounts);
            }
            return accounts;
        }

        migrateOldData();

        let Share = Lib.getV("Share", {});
        if (typeof Share === "string") {
            Share = JSON.parse(Share);
        }
        const CreateMenu = async Modal => {
            Lib.$q(".modal-background")?.remove();
            $("body").append(Modal.replace(/>\s+</g, "><"));
            requestAnimationFrame(() => {
                $(".modal-background").css({
                    opacity: "1",
                    "background-color": "rgba(0,0,0,0.7)"
                });
            });
        };
        const DeleteMenu = async () => {
            const modal = $(".modal-background");
            modal.css({
                opacity: "0",
                "pointer-events": "none",
                "background-color": "rgba(0,0,0,0)"
            });
            setTimeout(() => {
                modal.remove();
            }, 300);
        };
        const RegisterMenu = async () => {
            Lib.unMenu("Check-1");
            Lib.unMenu("Account-1");
            Lib.unMenu("Inject-1");
            const defaultAccount = getDefaultAccount();
            const hasCookie = Boolean(defaultAccount);
            const state = Lib.getV("Login", hasCookie);
            Lib.regMenu({
                [state ? Transl("🟢 Enable Detection") : Transl("🔴 Disable Detection")]: {
                    func: () => {
                        if (state) Lib.setV("Login", false); else if (hasCookie) Lib.setV("Login", true); else {
                            AlertModal(Transl("No Saved Cookies - Cannot Enable Auto-Login"));
                            return;
                        }
                        RegisterMenu();
                    },
                    close: false
                }
            }, {
                name: "Check"
            });
            Lib.regMenu({
                [Transl("Inject Default")]: ManualInjection
            }, {
                name: "Inject"
            });
            Lib.regMenu({
                [Transl("Account Management")]: AccountManagement
            }, {
                name: "Account"
            });
        };
        const GlobalMenuToggle = async () => {
            Lib.storeListen(["Login"], listen => {
                listen.far && RegisterMenu();
            });
        };
        async function Injection() {
            const defaultAccount = getDefaultAccount();
            const login = Lib.getV("Login", Boolean(defaultAccount));
            if (login && defaultAccount) {
                let CurrentTime = new Date();
                let DetectionTime = Lib.local("DetectionTime");
                DetectionTime = DetectionTime ? new Date(DetectionTime) : new Date(CurrentTime.getTime() + 11 * 60 * 1e3);
                const Conversion = Math.abs(DetectionTime - CurrentTime) / (1e3 * 60);
                if (Conversion >= 10) $Cookie.Verify(defaultAccount.cookies);
            }
            RegisterMenu();
            GlobalMenuToggle();
        }
        async function SharedLogin() {
            const Igneous = $Cookie.Get().igneous;
            const AccountQuantity = Object.keys(Share).length;
            let Select = $(`<select id="account-select" class="acc-select"></select>`), Value;
            for (let i = 1; i <= AccountQuantity; i++) {
                if (Share[i][0].value === Igneous) Value = i;
                Select.append($("<option>").attr({
                    value: i
                }).text(`${Transl("Account")} ${i}`));
            }
            CreateMenu(`
                <div class="modal-background">
                    <div class="acc-modal">
                        <h1>${Transl("Account Selection")}</h1>
                        <div class="acc-select-flex">${Select.prop("outerHTML")}</div>
                        <div class="acc-button-flex">
                            <button class="modal-button" id="update">${Transl("Update")}</button>
                            <button class="modal-button" id="login">${Transl("Login")}</button>
                        </div>
                    </div>
                </div>
            `);
            if (AccountQuantity === 0) {
                $("#account-select").append($("<option>")).prop("disabled", true);
            } else if (Value) $("#account-select").val(Value);
            $(".modal-background").on("click", function (click) {
                click.stopImmediatePropagation();
                const target = click.target;
                if (target.id === "login") {
                    $Cookie.ReAdd(Share[+$("#account-select").val()]);
                } else if (target.id === "update") {
                    $Shared.Update().then(Data => {
                        if (Data) {
                            Share = Data;
                            Lib.setJV("Share", Data);
                            setTimeout(SharedLogin, 600);
                        }
                    });
                } else if (target.className === "modal-background") {
                    DeleteMenu();
                }
            });
        }
        async function Cookie_Show(cookies) {
            CreateMenu(`
                <div class="modal-background">
                    <div class="show-modal">
                    <h1 style="text-align: center;">${Transl("Confirm Selected Cookies")}</h1>
                        <pre><b>${JSON.stringify(cookies, null, 4)}</b></pre>
                        <div class="set-box">
                            <label>${Transl("Note")}:</label>
                            <input class="set-list" type="text" id="cookie-note" placeholder="${Transl("Note")}">
                        </div>
                        <div style="text-align: right;">
                            <button class="modal-button" id="save">${Transl("Confirm Save")}</button>
                            <button class="modal-button" id="close">${Transl("Cancel")}</button>
                        </div>
                    </div>
                </div>
            `);
            $(".modal-background").on("click", function (click) {
                click.stopImmediatePropagation();
                const target = click.target;
                if (target.id === "save") {
                    const note = $("#cookie-note").val().trim();
                    addAccount(cookies, note);
                    Growl(Transl("Save Successful!"), 1500);
                    DeleteMenu();
                } else if (target.className === "modal-background" || target.id === "close") {
                    DeleteMenu();
                }
            });
        }
        async function AutoGetCookie() {
            let cookie_box = [];
            for (const [name, value] of Object.entries($Cookie.Get())) {
                cookie_box.push({
                    name: name,
                    value: value
                });
            }
            cookie_box.length > 1 ? Cookie_Show(cookie_box) : AlertModal(Transl("No Cookies Retrieved!\n\nPlease Login First"));
        }
        async function ManualSetting() {
            CreateMenu(`
                <div class="modal-background">
                    <div class="set-modal">
                    <h1>${Transl("Set Cookies")}</h1>
                        <form id="set_cookies">
                            <div id="input_cookies" class="set-box">
                                <label>${Transl("Note")}:</label><input class="set-list" type="text" id="manual-note" placeholder="${Transl("Note")}"><br>
                                <label>[igneous]:</label><input class="set-list" type="text" name="igneous" placeholder="${Transl("Required for Ex Login Only")}"><br>
                                <label>[ipb_member_id]:</label><input class="set-list" type="text" name="ipb_member_id" placeholder="${Transl("Required Field")}" required><br>
                                <label>[ipb_pass_hash]:</label><input class="set-list" type="text" name="ipb_pass_hash" placeholder="${Transl("Required Field")}" required><hr>
                                <h3>${Transl("Optional Fields Below")}</h3>
                                <label>[sl]:</label><input class="set-list" type="text" name="sl" value="dm_2"><br>
                                <label>[sk]:</label><input class="set-list" type="text" name="sk"><br>
                            </div>
                            <button type="submit" class="modal-button" id="save">${Transl("Confirm Save")}</button>
                            <button class="modal-button" id="close">${Transl("Exit Menu")}</button>
                        </form>
                    </div>
                </div>
            `);
            let cookie;
            const textarea = $("<textarea>").attr({
                style: "margin: 1.15rem auto 0 auto",
                rows: 18,
                cols: 40,
                readonly: true
            });
            $("#set_cookies").on("submit", function (submit) {
                submit.preventDefault();
                submit.stopImmediatePropagation();
                cookie = Array.from($("#set_cookies .set-list")).map(function (input) {
                    if (input.id === "manual-note") return null;
                    const value = $(input).val();
                    return value.trim() !== "" ? {
                        name: $(input).attr("name"),
                        value: value
                    } : null;
                }).filter(Boolean);
                textarea.val(JSON.stringify(cookie, null, 4));
                $("#set_cookies div").append(textarea);
                Growl(Transl("[Confirm Input Correct] Press Exit to Save"), 2500);
            });
            $(".modal-background").on("click", function (click) {
                click.stopImmediatePropagation();
                const target = click.target;
                if (target.className === "modal-background" || target.id === "close") {
                    click.preventDefault();
                    if (target.id === "close" && cookie) {
                        const note = $("#manual-note").val().trim();
                        addAccount(cookie, note);
                    }
                    DeleteMenu();
                }
            });
        }
        async function AccountManagement() {
            let accounts = getAccounts();
            const savedTab = Lib.getV("AccountTab", "local");
            let currentTab = savedTab;

            const renderLocalTab = () => {
                const container = $("#account-list");
                container.empty();
                if (accounts.length === 0) {
                    container.append(`<p style="text-align:center;opacity:0.6;">${Transl("No accounts saved")}</p>`);
                    renderCurrentLogin();
                    return;
                }
                accounts.forEach((account, index) => {
                    const isDefault = account.isDefault;
                    const item = $(`
                        <div class="account-item" data-id="${account.id}">
                            <span class="account-index">#${index + 1}${isDefault ? ` (${Transl("Default")})` : ""}</span>
                            <input class="account-note" placeholder="${Transl("Note")}">
                            <button class="account-action view-cookies">${account.cookies.length} cookies</button>
                            <button class="account-action set-default" ${isDefault ? "disabled" : ""}>${Transl("Set as Default")}</button>
                            <button class="account-action inject-account">${Transl("Inject")}</button>
                        </div>
                    `);
                    item.find(".account-note").val(account.note || "");
                    container.append(item);
                });
                renderCurrentLogin();
            };

            const renderCurrentLogin = () => {
                const el = $("#current-login");
                if (!el.length) return;
                const currentId = $Cookie.Get().ipb_member_id;
                if (!currentId) {
                    el.text(`${Transl("Current Login")}: ${Transl("Not logged in")}`);
                    return;
                }
                const matches = getAccounts()
                    .map((a, i) => ({ i: i + 1, note: a.note || "", id: (a.cookies || []).find(c => c.name === "ipb_member_id")?.value }))
                    .filter(m => m.id != null && m.id === currentId);
                let text = `${Transl("Current Login")}: ${currentId}`;
                if (matches.length) {
                    text += ` (${matches.map(m => `#${m.i} ${m.note || "user"}`).join(", ")})`;
                }
                el.text(text);
            };
            const renderSharedTab = () => {
                const container = $("#shared-content");
                container.empty();
                const Igneous = $Cookie.Get().igneous;
                const AccountQuantity = Object.keys(Share).length;
                let Select = $(`<select id="share-select" class="acc-select"></select>`), Value;
                for (let i = 1; i <= AccountQuantity; i++) {
                    if (Share[i][0].value === Igneous) Value = i;
                    Select.append($("<option>").attr({ value: i }).text(`${Transl("Account")} ${i}`));
                }
                container.append(`
                    <div class="set-box">
                        <label>${Transl("Shared Data URL")}:</label>
                        <input class="set-list" type="url" id="share-url" value="${Lib.getV("ShareURL", "").replace(/&/g, "&amp;").replace(/"/g, "&quot;")}">
                    </div>
                    <div class="acc-select-flex">${Select.prop("outerHTML")}</div>
                    <div class="acc-button-flex">
                        <button class="modal-button" id="share-update">${Transl("Update")}</button>
                        <button class="modal-button" id="share-login">${Transl("Login")}</button>
                    </div>
                `);
                if (AccountQuantity === 0) {
                    $("#share-select").append($("<option>")).prop("disabled", true);
                } else if (Value) $("#share-select").val(Value);
            };

            const switchTab = (tab) => {
                currentTab = tab;
                Lib.setV("AccountTab", tab);
                $(".tab-btn").removeClass("active");
                $(`#tab-${tab}`).addClass("active");
                $(".tab-content").hide();
                $(`#tab-content-${tab}`).show();
            };

            const showCookies = account => {
                const index = getAccounts().findIndex(a => a.id === account.id);
                const label = account.note || `${Transl("Account")} ${index + 1}`;
                const modal = $(`
                    <div class="modal-background">
                        <div class="show-modal">
                            <h1 style="text-align:center;">${label}</h1>
                            <textarea id="cookie-editor" rows="14" spellcheck="false" style="width:100%;box-sizing:border-box;resize:vertical;font-family:monospace;font-size:1rem;background:transparent;color:inherit;">${JSON.stringify(account.cookies, null, 4).replace(/&/g, "&amp;").replace(/</g, "&lt;")}</textarea>
                            <div style="text-align:right;">
                                <button class="modal-button" id="cookie-delete">${Transl("Delete")}</button>
                                <button class="modal-button" id="cookie-close">${Transl("Close")}</button>
                                <button class="modal-button" id="cookie-save">${Transl("Save")}</button>
                            </div>
                        </div>
                    </div>
                `).appendTo("body");
                requestAnimationFrame(() => modal.css({ opacity: "1", "background-color": "rgba(0,0,0,0.7)" }));
                const close = () => {
                    modal.css({ opacity: "0", "pointer-events": "none", "background-color": "rgba(0,0,0,0)" });
                    setTimeout(() => modal.remove(), 300);
                };
                modal.on("click", async function (click) {
                    const target = click.target;
                    if (target.id === "cookie-close" || target.className === "modal-background") {
                        close();
                    } else if (target.id === "cookie-save") {
                        try {
                            const parsed = JSON.parse(modal.find("#cookie-editor").val());
                            if (!Array.isArray(parsed)) throw new Error();
                            accounts = updateAccountCookies(account.id, parsed);
                            close();
                            Growl(Transl("Changes Saved"), 1500);
                        } catch (error) {
                            modal.find(".cookie-error").remove();
                            modal.find("h1").after(`<p class="cookie-error" style="color:#e0483d;">${Transl("Invalid JSON")}</p>`);
                        }
                    } else if (target.id === "cookie-delete") {
                        if (await ConfirmModal(Transl("Are you sure you want to delete this account?"))) {
                            accounts = deleteAccount(account.id);
                            renderLocalTab();
                            close();
                            Growl(Transl("Account deleted"), 1500);
                        }
                    }
                });
            };

            CreateMenu(`
                <div class="modal-background">
                    <div class="set-modal" style="width:50%;">
                        <h1>${Transl("Account Management")}</h1>
                        <div class="current-login" id="current-login"></div>
                        <div class="tab-bar">
                            <button id="tab-local" class="tab-btn">${Transl("Local Accounts")}</button>
                            <button id="tab-shared" class="tab-btn">${Transl("Shared Accounts")}</button>
                        </div>
                        <div id="tab-content-local" class="tab-content">
                            <div class="account-list" id="account-list"></div>
                            <div class="tab-actions">
                                <button class="modal-button" id="auto-get">${Transl("Auto Retrieve")}</button>
                                <button class="modal-button" id="manual-set">${Transl("Manual Input")}</button>
                                <button class="modal-button" id="clear-login">${Transl("Clear Login")}</button>
                            </div>
                        </div>
                        <div id="tab-content-shared" class="tab-content">
                            <div id="shared-content"></div>
                        </div>
                        <button class="modal-button" id="close">${Transl("Exit Menu")}</button>
                    </div>
                </div>
            `);

            switchTab(currentTab);
            renderLocalTab();
            renderSharedTab();

            $("#tab-local").on("click", () => switchTab("local"));
            $("#tab-shared").on("click", () => switchTab("shared"));

            $("#auto-get").on("click", () => { DeleteMenu(); setTimeout(AutoGetCookie, 100); });
            $("#manual-set").on("click", () => { DeleteMenu(); setTimeout(ManualSetting, 100); });
            $("#clear-login").on("click", async () => {
                if (await ConfirmModal(Transl("Are you sure you want to clear current login information? This will not affect saved cookies."))) {
                    DeleteMenu();
                    ClearLogin();
                }
            });

            $("#share-login").on("click", () => {
                $Cookie.ReAdd(Share[+$("#share-select").val()]);
            });
            $("#share-update").on("click", () => {
                $Shared.Update().then(Data => {
                    if (Data) {
                        Share = Data;
                        Lib.setJV("Share", Data);
                        renderSharedTab();
                    }
                });
            });

            $(".modal-background").on("input", ".account-note", function () {
                const id = $(this).closest(".account-item").attr("data-id");
                accounts = updateAccountNote(id, $(this).val().trim());
            });

            $(".modal-background").on("input", "#share-url", function () {
                Lib.setV("ShareURL", $(this).val().trim());
            });

            $(".modal-background").on("click", "button.view-cookies", function () {
                const id = $(this).closest(".account-item").attr("data-id");
                const account = accounts.find(a => a.id === id);
                if (account) showCookies(account);
            });

            $(".modal-background").on("click", "button.inject-account", function () {
                const id = $(this).closest(".account-item").attr("data-id");
                const account = accounts.find(a => a.id === id);
                if (account) $Cookie.ReAdd(account.cookies);
            });

            $(".modal-background").on("click", "button.set-default", function () {
                const id = $(this).closest(".account-item").attr("data-id");
                accounts = setDefaultAccount(id);
                renderLocalTab();
            });

            $(".modal-background").on("click", function (click) {
                if (click.target.className === "modal-background" || click.target.id === "close") {
                    DeleteMenu();
                }
            });
        }
        async function ManualInjection() {
            const defaultAccount = getDefaultAccount();
            if (!defaultAccount) {
                AlertModal(Transl("No Injectable Cookies!\n\nConfigure in Menu"));
                return;
            }
            $Cookie.ReAdd(defaultAccount.cookies);
        }
        async function ClearLogin() {
            $Cookie.Delete();
            location.reload();
        }
        return {
            Injection: Injection
        };
    })(CookieFactory(), SharedFactory()).then(Main => {
        Main.Injection();
    });
    function Growl(message, life = 2000) {
        let container = $(".toast-container");
        if (!container.length) {
            container = $('<div class="toast-container"></div>').appendTo("body");
        }
        const toast = $('<div class="toast"></div>').text(message).appendTo(container);
        requestAnimationFrame(() => toast.addClass("show"));
        setTimeout(() => {
            toast.removeClass("show");
            setTimeout(() => toast.remove(), 250);
        }, life);
    }
    function ModalLayer(inner, ids) {
        return new Promise(resolve => {
            const modal = $(
                `<div class="modal-background">
                    <div class="show-modal" style="text-align:center;">
                        <p style="margin:1rem 0;">${inner}</p>
                        <div style="text-align:right;">
                            <button class="modal-button" id="${ids[0]}">${Transl("Cancel")}</button>
                            ${ids[1] ? `<button class="modal-button" id="${ids[1]}">${Transl("Confirm")}</button>` : ""}
                        </div>
                    </div>
                </div>`
            ).appendTo("body");
            requestAnimationFrame(() => modal.css({ opacity: "1", "background-color": "rgba(0,0,0,0.7)" }));
            const close = result => {
                modal.css({ opacity: "0", "pointer-events": "none", "background-color": "rgba(0,0,0,0)" });
                setTimeout(() => modal.remove(), 300);
                resolve(result);
            };
            modal.on("click", function (click) {
                const target = click.target;
                if (target.id === ids[1]) close(true);
                else if (target.id === ids[0] || target.className === "modal-background") close(ids[1] ? false : true);
            });
        });
    }
    const AlertModal = message => ModalLayer(message, ["alert-ok"]);
    const ConfirmModal = message => ModalLayer(message, ["confirm-no", "confirm-yes"]);
    function SharedFactory() {
        async function Get() {
            const url = Lib.getV("ShareURL", "");
            if (!url) {
                AlertModal(Transl("Please set the Shared Data URL first"));
                return {};
            }
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: "GET",
                    responseType: "json",
                    url: url,
                    onload: response => {
                        if (response.status === 200) {
                            const data = response.response;
                            if (typeof data === "object" && Object.keys(data).length > 0) {
                                resolve(data);
                            } else {
                                console.error(Transl("Request Empty Data"));
                                resolve({});
                            }
                        } else {
                            console.error(Transl("Connection Error - Update Address May Be Wrong"));
                            resolve({});
                        }
                    },
                    onerror: error => {
                        console.error(Transl("Request Error: "), error);
                        resolve({});
                    }
                });
            });
        }
        async function Update() {
            const Shared = await Get();
            if (Object.keys(Shared).length > 0) {
                const localHash = md5(Lib.getV("Share", ""));
                const remoteHash = md5(JSON.stringify(Shared));
                if (localHash !== remoteHash) {
                    Growl(Transl("Shared Data Update Complete"), 1500);
                    return Shared;
                } else {
                    Growl(Transl("Shared Data Update Not Needed"), 1500);
                }
            } else {
                Growl(Transl("Shared Data Retrieval Failed"), 2500);
            }
            return false;
        }
        return {
            Update: Update
        };
    }
    function CookieFactory() {
        const Today = new Date();
        Today.setFullYear(Today.getFullYear() + 1);
        const Expires = Today.toUTCString();
        const UnixUTC = new Date(0).toUTCString();
        let RequiredCookie = ["ipb_member_id", "ipb_pass_hash"];
        if (domain == "exhentai.org") RequiredCookie.unshift("igneous");
        return {
            Get: () => {
                return Lib.cookie().split("; ").reduce((acc, cookie) => {
                    const [name, value] = cookie.split("=");
                    acc[decodeURIComponent(name)] = decodeURIComponent(value);
                    return acc;
                }, {});
            },
            Add: function (CookieObject) {
                Lib.local("DetectionTime", {
                    value: Lib.getDate()
                });
                for (const Cookie of CookieObject) {
                    Lib.cookie(`${encodeURIComponent(Cookie.name)}=${encodeURIComponent(Cookie.value)}; domain=.${domain}; path=/; expires=${Expires};`);
                }
                location.reload();
            },
            Delete: function () {
                Object.keys(this.Get()).forEach(Name => {
                    Lib.cookie(`${Name}=; expires=${UnixUTC}; path=/;`);
                    Lib.cookie(`${Name}=; expires=${UnixUTC}; path=/; domain=.${domain}`);
                });
            },
            ReAdd: function (Cookies) {
                this.Delete();
                this.Add(Cookies);
            },
            Verify: function (Cookies) {
                const Cookie = this.Get();
                const VCookie = new Set(Object.keys(Cookie));
                const Result = RequiredCookie.every(key => VCookie.has(key) && Cookie[key] !== "mystery");
                if (!Result) {
                    this.ReAdd(Cookies);
                } else {
                    Lib.local("DetectionTime", {
                        value: Lib.getDate()
                    });
                }
            }
        };
    }
    function Language() {
        const Word = Lib.translMatcher({
            English: {},
            Traditional: {
                "Auto Retrieve": "自動獲取",
                "Manual Input": "手動輸入",
                "Inject Default": "注入默認",
                "Clear Login": "清除登入",
                "🟢 Enable Detection": "🟢 啟用檢測",
                "🔴 Disable Detection": "🔴 禁用檢測",
                "Account": "帳戶",
                "Update": "更新",
                "Login": "登入",
                "Confirm Selected Cookies": "確認選擇的 Cookies",
                "Confirm Save": "確認保存",
                "Cancel": "取消退出",
                "Exit Menu": "退出選單",
                "Save Successful!": "保存成功!",
                "Set Cookies": "設置 Cookies",
                "Required for Ex Login Only": "要登入 Ex 才需要填寫",
                "Required Field": "必填項目",
                "Optional Fields Below": "下方選填 也可不修改",
                "[Confirm Input Correct] Press Exit to Save": "[確認輸入正確] 按下退出選單保存",
                "Current Cookie Settings": "當前設置 Cookies",
                "Account Selection": "帳戶選擇",
                "No Cookies Retrieved!\n\nPlease Login First": "未獲取到 Cookies !!\n\n請先登入帳戶",
                "No Injectable Cookies!\n\nConfigure in Menu": "未檢測到可注入的 Cookies !!\n\n請從選單中進行設置",
                "Shared Data Update Complete": "共享數據更新完成",
                "Shared Data Update Not Needed": "共享數據無需更新",
                "Shared Data Retrieval Failed": "共享數據獲取失敗",
                "No Saved Cookies - Cannot Enable Auto-Login": "無保存的 Cookie, 無法啟用自動登入",
                "Request Empty Data": "請求為空數據",
                "Connection Error - Update Address May Be Wrong": "連線異常,更新地址可能是錯的",
                "Request Error: ": "請求錯誤: ",
                "Note": "備註",
                "Default": "默認",
                "No accounts saved": "無已保存賬號",
                "Delete": "刪除",
                "Close": "關閉",
                "Inject": "注入",
                "Account deleted": "賬號已刪除",
                "Account Management": "賬號管理",
                "Current Login": "當前登入",
                "Not logged in": "未登入",
                "Local Accounts": "本地賬號",
                "Shared Accounts": "共享賬號",
                "Set as Default": "設為默認",
                "Are you sure you want to delete this account?": "確定要刪除此賬號嗎?",
                "Are you sure you want to clear current login information? This will not affect saved cookies.": "確定要清除當前登入信息嗎?這不會影響已保存的 cookies。",
                "Shared Data URL": "共享數據URL",
                "Please set the Shared Data URL first": "請先設置共享數據URL"
            },
            Simplified: {
                "Auto Retrieve": "自动获取",
                "Manual Input": "手动输入",
                "Inject Default": "注入默认",
                "Clear Login": "清除登录信息",
                "🟢 Enable Detection": "🟢 启用检测",
                "🔴 Disable Detection": "🔴 禁用检测",
                "Account": "账号",
                "Update": "更新",
                "Login": "登录",
                "Confirm Selected Cookies": "确认所选 Cookies",
                "Confirm Save": "确认保存",
                "Cancel": "取消",
                "Exit Menu": "关闭菜单",
                "Save Successful!": "保存成功!",
                "Set Cookies": "设置 Cookies",
                "Required for Ex Login Only": "仅登录 Ex 时需要填写",
                "Required Field": "必填项",
                "Optional Fields Below": "以下为选填项,可不修改",
                "[Confirm Input Correct] Press Exit to Save": "[确认输入无误] 点击关闭菜单保存",
                "Current Cookie Settings": "当前 Cookies 设置",
                "Account Selection": "选择账号",
                "No Cookies Retrieved!\n\nPlease Login First": "未获取到 Cookies!\n\n请先登录账号",
                "No Injectable Cookies!\n\nConfigure in Menu": "未检测到可注入的 Cookies!\n\n请在菜单中进行设置",
                "Shared Data Update Complete": "共享数据更新完成",
                "Shared Data Update Not Needed": "共享数据无需更新",
                "Shared Data Retrieval Failed": "共享数据获取失败",
                "No Saved Cookies - Cannot Enable Auto-Login": "没有已保存的 Cookie,无法启用自动登录",
                "Request Empty Data": "请求数据为空",
                "Connection Error - Update Address May Be Wrong": "连接异常,更新地址可能不正确",
                "Request Error: ": "请求错误:",
                "Note": "备注",
                "Default": "默认",
                "No accounts saved": "无已保存账号",
                "Delete": "删除",
                "Close": "关闭",
                "Inject": "注入",
                "Account deleted": "账号已删除",
                "Account Management": "账号管理",
                "Current Login": "当前登入",
                "Not logged in": "未登录",
                "Local Accounts": "本地账号",
                "Shared Accounts": "共享账号",
                "Set as Default": "设为默认",
                "Are you sure you want to delete this account?": "确定要删除此账号吗?",
                "Are you sure you want to clear current login information? This will not affect saved cookies.": "确定要清除当前登入信息吗?这不会影响已保存的cookies。",
                "Shared Data URL": "共享数据URL",
                "Please set the Shared Data URL first": "请先设置共享数据URL"
            },
            Japan: {
                "Auto Retrieve": "自動取得",
                "Manual Input": "手動入力",
                "Inject Default": "デフォルト注入",
                "Clear Login": "ログインをクリア",
                "🟢 Enable Detection": "🟢 検出を有効化",
                "🔴 Disable Detection": "🔴 検出を無効化",
                "Account": "アカウント",
                "Update": "更新",
                "Login": "ログイン",
                "Confirm Selected Cookies": "選択したCookieを確認",
                "Confirm Save": "保存を確認",
                "Cancel": "終了をキャンセル",
                "Exit Menu": "メニューを終了",
                "Save Successful!": "保存に成功しました!",
                "Set Cookies": "Cookieを設定",
                "Required for Ex Login Only": "Exログインにのみ必要",
                "Required Field": "必須項目",
                "Optional Fields Below": "以下は任意、変更しなくても構いません",
                "[Confirm Input Correct] Press Exit to Save": "[入力が正しいことを確認] メニュー終了を押して保存",
                "Current Cookie Settings": "現在のCookie設定",
                "Account Selection": "アカウント選択",
                "No Cookies Retrieved!\n\nPlease Login First": "Cookieを取得できませんでした!\n\nまずアカウントにログインしてください",
                "No Injectable Cookies!\n\nConfigure in Menu": "注入可能なCookieが検出されませんでした!\n\nメニューから設定してください",
                "Shared Data Update Complete": "共有データの更新が完了しました",
                "Shared Data Update Not Needed": "共有データの更新は不要です",
                "Shared Data Retrieval Failed": "共有データの取得に失敗しました",
                "No Saved Cookies - Cannot Enable Auto-Login": "保存されたCookieがないため、自動ログインを有効にできません",
                "Request Empty Data": "リクエストにデータがありません",
                "Connection Error - Update Address May Be Wrong": "接続エラー、更新アドレスが間違っている可能性があります",
                "Request Error: ": "リクエストエラー: ",
                "Note": "メモ",
                "Default": "デフォルト",
                "No accounts saved": "保存されたアカウントがありません",
                "Delete": "削除",
                "Close": "閉じる",
                "Inject": "注入",
                "Account deleted": "アカウントを削除しました",
                "Account Management": "アカウント管理",
                "Current Login": "現在ログイン中",
                "Not logged in": "未ログイン",
                "Local Accounts": "ローカルアカウント",
                "Shared Accounts": "共有アカウント",
                "Set as Default": "デフォルトに設定",
                "Are you sure you want to delete this account?": "このアカウントを削除してもよろしいですか?",
                "Are you sure you want to clear current login information? This will not affect saved cookies.": "現在のログイン情報を消去してもよろしいですか?保存済みのCookieには影響しません。",
                "Shared Data URL": "共有データURL",
                "Please set the Shared Data URL first": "まず共有データURLを設定してください"
            },
            Korea: {
                "Auto Retrieve": "자동 가져오기",
                "Manual Input": "수동 입력",
                "Inject Default": "기본 주입",
                "Clear Login": "로그인 정보 삭제",
                "🟢 Enable Detection": "🟢 감지 활성화",
                "🔴 Disable Detection": "🔴 감지 비활성화",
                "Account": "계정",
                "Update": "업데이트",
                "Login": "로그인",
                "Confirm Selected Cookies": "선택한 쿠키 확인",
                "Confirm Save": "저장 확인",
                "Cancel": "종료 취소",
                "Exit Menu": "메뉴 종료",
                "Save Successful!": "저장 성공!",
                "Set Cookies": "쿠키 설정",
                "Required for Ex Login Only": "Ex 로그인에만 필요",
                "Required Field": "필수 항목",
                "Optional Fields Below": "아래는 선택사항, 변경하지 않아도 됩니다",
                "[Confirm Input Correct] Press Exit to Save": "[입력이 정확한지 확인] 메뉴 종료를 눌러 저장",
                "Current Cookie Settings": "현재 설정된 쿠키",
                "Account Selection": "계정 선택",
                "No Cookies Retrieved!\n\nPlease Login First": "쿠키를 가져오지 못했습니다!\n\n먼저 계정에 로그인해 주세요",
                "No Injectable Cookies!\n\nConfigure in Menu": "주입 가능한 쿠키가 감지되지 않았습니다!\n\n메뉴에서 설정해 주세요",
                "Shared Data Update Complete": "공유 데이터 업데이트 완료",
                "Shared Data Update Not Needed": "공유 데이터 업데이트 불필요",
                "Shared Data Retrieval Failed": "공유 데이터 가져오기 실패",
                "No Saved Cookies - Cannot Enable Auto-Login": "저장된 쿠키가 없어 자동 로그인을 활성화할 수 없습니다",
                "Request Empty Data": "요청에 데이터가 없습니다",
                "Connection Error - Update Address May Be Wrong": "연결 오류, 업데이트 주소가 잘못되었을 수 있습니다",
                "Request Error: ": "요청 오류: ",
                "Note": "메모",
                "Default": "기본",
                "No accounts saved": "저장된 계정이 없습니다",
                "Delete": "삭제",
                "Close": "닫기",
                "Inject": "주입",
                "Account deleted": "계정이 삭제되었습니다",
                "Account Management": "계정 관리",
                "Current Login": "현재 로그인",
                "Not logged in": "로그인 안 됨",
                "Local Accounts": "로컬 계정",
                "Shared Accounts": "공유 계정",
                "Set as Default": "기본값으로 설정",
                "Are you sure you want to delete this account?": "이 계정을 삭제하시겠습니까?",
                "Are you sure you want to clear current login information? This will not affect saved cookies.": "현재 로그인 정보를 삭제하시겠습니까? 저장된 쿠키에는 영향을 주지 않습니다.",
                "Shared Data URL": "공유 데이터 URL",
                "Please set the Shared Data URL first": "먼저 공유 데이터 URL을 설정해 주세요"
            },
            Russia: {
                "Auto Retrieve": "Автоматическое получение",
                "Manual Input": "Ручной ввод",
                "Inject Default": "Внедрить по умолчанию",
                "Clear Login": "Очистить вход",
                "🟢 Enable Detection": "🟢 Включить обнаружение",
                "🔴 Disable Detection": "🔴 Отключить обнаружение",
                "Account": "Аккаунт",
                "Update": "Обновить",
                "Login": "Войти",
                "Confirm Selected Cookies": "Подтвердить выбранные Cookies",
                "Confirm Save": "Подтвердить сохранение",
                "Cancel": "Отменить выход",
                "Exit Menu": "Выйти из меню",
                "Save Successful!": "Сохранение успешно!",
                "Set Cookies": "Настройка Cookies",
                "Required for Ex Login Only": "Требуется только для входа в Ex",
                "Required Field": "Обязательное поле",
                "Optional Fields Below": "Необязательно ниже, изменения не требуются",
                "[Confirm Input Correct] Press Exit to Save": "[Подтвердите правильность ввода] Нажмите Выйти из меню для сохранения",
                "Current Cookie Settings": "Текущие настройки Cookies",
                "Account Selection": "Выбор аккаунта",
                "No Cookies Retrieved!\n\nPlease Login First": "Cookies не получены !!\n\nПожалуйста, сначала войдите в аккаунт",
                "No Injectable Cookies!\n\nConfigure in Menu": "Не обнаружены Cookies для внедрения !!\n\nПожалуйста, настройте в меню",
                "Shared Data Update Complete": "Обновление общих данных завершено",
                "Shared Data Update Not Needed": "Обновление общих данных не требуется",
                "Shared Data Retrieval Failed": "Ошибка получения общих данных",
                "No Saved Cookies - Cannot Enable Auto-Login": "Нет сохраненных cookies, невозможно включить автоматический вход",
                "Request Empty Data": "Запрос содержит пустые данные",
                "Connection Error - Update Address May Be Wrong": "Ошибка соединения, адрес обновления может быть неверным",
                "Request Error: ": "Ошибка запроса: ",
                "Note": "Заметка",
                "Default": "По умолчанию",
                "No accounts saved": "Нет сохраненных аккаунтов",
                "Delete": "Удалить",
                "Close": "Закрыть",
                "Inject": "Внедрить",
                "Account deleted": "Аккаунт удален",
                "Account Management": "Управление аккаунтами",
                "Current Login": "Текущий вход",
                "Not logged in": "Не выполнен",
                "Local Accounts": "Локальные аккаунты",
                "Shared Accounts": "Общие аккаунты",
                "Set as Default": "Сделать основным",
                "Are you sure you want to delete this account?": "Вы уверены, что хотите удалить этот аккаунт?",
                "Are you sure you want to clear current login information? This will not affect saved cookies.": "Вы уверены, что хотите очистить текущие данные входа? Это не повлияет на сохраненные cookies.",
                "Shared Data URL": "URL общих данных",
                "Please set the Shared Data URL first": "Сначала укажите URL общих данных"
            }
        });
        return {
            Transl: Str => Word[Str] ?? Str
        };
    }
})();