[Eh] 계정 관리

Eh 계정 관리 - 자동 로그인 및 다중 계정 전환, 공유 계정 및 cookie 가져오기/내보내기 지원, greasyfork.org/scripts/470710 에서 수정

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==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
        };
    }
})();