MWI Simulator Auto Import

Tools for Milky Way Idle Combat Simulator. Automatically imports set group settings from URL parameters. Also provides a share feature to share the current settings to online storage.

安装此脚本
作者推荐脚本

您可能也喜欢Real Profit Calculator

安装此脚本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         MWI Simulator Auto Import
// @namespace    http://tampermonkey.net/
// @version      0.1.1
// @description  Tools for Milky Way Idle Combat Simulator. Automatically imports set group settings from URL parameters. Also provides a share feature to share the current settings to online storage.
// @homepage     https://github.com/leonardodalinky/MWI-Simulator-Auto-Import
// @author       AyajiLin
// @match        https://amvoidguy.github.io/MWICombatSimulatorTest/*
// @match        https://shykai.github.io/MWICombatSimulatorTest/dist/*
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @connect      api.textdb.online
// @license      MIT
// @run-at       document-end
// ==/UserScript==

unsafeWindow.isAlertEnabled = true;

(function () {
    'use strict';

    /////////////////////
    //                 //
    //    Utilities    //
    //                 //
    /////////////////////
    // Function to create and show a floating message
    function showFloatingMessage(message, options = {}) {
        const messageDiv = document.createElement('div');
        messageDiv.style.cssText = `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background-color: ${options.backgroundColor || 'rgba(0, 0, 0, 0.8)'};
            color: white;
            padding: 10px 20px;
            border-radius: 5px;
            z-index: 9999;
            font-family: Arial, sans-serif;
            font-size: 14px;
            transition: opacity 0.3s ease-in-out;
        `;
        messageDiv.textContent = message;
        document.body.appendChild(messageDiv);

        // Auto-remove after delay (default: 3 seconds)
        const duration = options.duration || 3000;
        if (duration > 0) {
            setTimeout(() => {
                messageDiv.style.opacity = '0';
                setTimeout(() => messageDiv.remove(), 300); // Match the CSS transition
            }, duration);
        }

        
        return messageDiv;
    }

    // Function to show error message
    function showErrorMessage(message, duration = 3000) {
        return showFloatingMessage(message, {
            backgroundColor: 'rgba(220, 53, 69, 0.9)', // Bootstrap danger color
            duration: duration
        });
    }

    // Function to show success message
    function showSuccessMessage(message, duration = 3000) {
        return showFloatingMessage(message, {
            backgroundColor: 'rgba(25, 135, 84, 0.9)', // Bootstrap success color
            duration: duration
        });
    }

    function clickGetPriceButton() {
        const getPriceButton = document.querySelector(`button#buttonGetPrices`);
        if (getPriceButton) {
            console.log("Click getPriceButton");
            getPriceButton.click();
        }
    }

    async function getGroupJson() {
        // Temporary disable alert
        unsafeWindow.isAlertEnabled = false;
        document.querySelector(`a#group-combat-tab`).click();
        document.getElementById('buttonExportSet').click();
        // Get json from clipboard
        const json = await navigator.clipboard.readText().finally(() => {
            unsafeWindow.isAlertEnabled = true;
        });
        return json;
    }

    //////////////////////
    //                  //
    //    TextDB API    //
    //                  //
    //////////////////////
    // Generate a random TextDB key (20-40 characters long)
    function generateTextDBKey() {
        const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_';
        const keyLength = 20 + Math.floor(Math.random() * 11); // Random length between 20 and 30
        let result = '';
        const randomValues = new Uint32Array(keyLength);
        window.crypto.getRandomValues(randomValues);
        
        for (let i = 0; i < keyLength; i++) {
            result += chars[randomValues[i] % chars.length];
        }
        return result;
    }

    async function save2TextDB(text) {
        // Generate a random key for TextDB
        let key = generateTextDBKey();
        console.log('Generated TextDB key:', key);

        // Encode the parameters for x-www-form-urlencoded
        const params = new URLSearchParams();
        params.append('key', key);
        params.append('value', text);

        // Check if the key already exists
        const checkResponse = await new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://api.textdb.online/${encodeURIComponent(key)}`,
                onload: resolve,
                onerror: (error) => resolve({ status: 500, responseText: '' })
            });
        });
        
        if (checkResponse.status === 200 && checkResponse.responseText) {
            console.log('Key already exists, generating a new one...');
            key = generateTextDBKey();
            params.set('key', key);
        }
        
        // Save text to textdb.online
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: 'https://api.textdb.online/update/',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                data: params.toString(),
                onload: function(response) {
                    try {
                        const result = JSON.parse(response.responseText);
                        if (response.status === 200 && result.status === 1) {
                            console.log('Text saved to TextDB successfully!', result);
                            resolve({
                                success: true,
                                key: result.data.key,
                                url: result.data.url,
                                reqId: result.req_id
                            });
                        } else {
                            console.error('Failed to save to TextDB:', result);
                            reject(new Error(`API Error: ${result.message || 'Unknown error'}`));
                        }
                    } catch (error) {
                        console.error('Error parsing API response:', error);
                        reject(new Error('Invalid response from TextDB API'));
                    }
                },
                onerror: function(error) {
                    console.error('Error saving to TextDB:', error);
                    reject(error);
                }
            });
        });
    }

    /////////////////
    //             //
    //    Share    //
    //             //
    /////////////////
    var shareURL = "";

    function showShareDialog() {
        const dialog = document.getElementById('shareModal');
        if (dialog) {
            dialog.style.display = "block";
            dialog.className = "modal show";
            dialog.ariaModal = "true";
            dialog.role = "dialog";
            dialog.removeAttribute("aria-hidden");
            document.body.classList.add("modal-open");
            document.body.style.overflow = "hidden";
            const modalBackdrop = document.createElement('div');
            modalBackdrop.className = "modal-backdrop show";
            document.body.appendChild(modalBackdrop);
        } else {
            console.error("Dialog not found");
        }
    }

    function hideShareDialog() {
        const dialog = document.getElementById('shareModal');
        if (dialog) {
            dialog.style.display = "none";
            dialog.className = "modal";
            dialog.removeAttribute("aria-modal");
            dialog.removeAttribute("role");
            document.body.classList.remove("modal-open");
            document.body.style.overflow = "";
            const modalBackdrop = document.querySelector('.modal-backdrop');
            if (modalBackdrop) {
                modalBackdrop.remove();
            }
        } else {
            console.error("Share Dialog not found");
        }
    }

    function enableCopyButton() {
        const button = document.getElementById('buttonCopyShareURL');
        if (button) {
            button.disabled = false;
        }
    }

    function copyShareURL() {
        navigator.clipboard.writeText(shareURL)
            .then(() => {
                console.log('Share URL copied to clipboard!', shareURL);
                showSuccessMessage('Share URL copied to clipboard!');
            })
            .catch(error => {
                console.error('Error copying URL to clipboard:', error);
                showErrorMessage('Failed to copy share URL to clipboard');
            });
    }

    function setShareURLText() {
        // Set share URL textbox value and scroll to the end
        const input = document.getElementById('shareURLText');
        if (input) {
            input.value = shareURL;
            // Scroll to the end of the input
            input.scrollLeft = input.scrollWidth;
            // Set selection to the end (optional, shows cursor at end)
            input.selectionStart = input.selectionEnd = shareURL.length;
        }
    }

    async function share2TextDB() {
        try {
            const json = await getGroupJson();
            const response = await save2TextDB(json);
            console.log('Text saved to TextDB successfully!', response);
            
            // Get the current page's base URL (without query parameters)
            const baseURL = window.location.href.split('?')[0];
            shareURL = `${baseURL}?textdb=${response.key}`;
            showSuccessMessage('Text saved to TextDB successfully!');
            setShareURLText();
            enableCopyButton();
        } catch (error) {
            console.error('Error sharing to TextDB:', error);
            showErrorMessage(error.message || 'Failed to share to TextDB');
        }
    }


    function addShareDialog() {
        const dialogHtml = `
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Share / 分享</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" id="buttonCloseShare1"></button>
                    </div>
                    <div class="modal-body">
                        <div class="container">
                            <div class="row mb-3">
                                <div class="col-12">
                                    <div class="input-group">
                                        <input type="text" class="form-control" id="shareURLText" value="Generated Share URL To Be Here..." readonly>
                                    </div>
                                </div>
                            </div>
                            <div class="row justify-content-center">
                                <div class="col-md-auto">
                                    <button type="button" class="btn btn-primary" id="buttonShareTextDB">TextDB</button>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-success" data-bs-dismiss="modal" id="buttonCopyShareURL" disabled>Copy URL/复制链接</button>
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="buttonCloseShare2">Close/关闭</button>
                    </div>
                </div>
            </div>
        `;
        const dialogDiv = document.createElement('div');
        dialogDiv.className = "modal";
        dialogDiv.id = "shareModal";
        dialogDiv.tabIndex = "-1";
        dialogDiv.style.display = "none";
        dialogDiv.ariaHidden = "true";
        dialogDiv.innerHTML = dialogHtml;
        const targetDiv = document.getElementById('houseRoomsModal');
        targetDiv.parentNode.insertBefore(dialogDiv, targetDiv.nextSibling);
        // Add `Share` button
        const button = document.createElement('button');
        button.id = "buttonShare";
        button.className = "btn btn-primary";
        button.type = "button";
        button.textContent = "Share/分享";
        button.onclick = showShareDialog;
        const buttonDiv = document.createElement('div');
        buttonDiv.className = "col-md-auto";
        buttonDiv.appendChild(button);
        const targetButton = document.getElementById('buttonImportExport');
        targetButton.parentNode.parentNode.insertBefore(buttonDiv, targetButton.parentNode.nextSibling);
        document.getElementById('buttonCloseShare1').onclick = hideShareDialog;
        document.getElementById('buttonCloseShare2').onclick = hideShareDialog;
        // Bind share logics
        document.getElementById('buttonShareTextDB').onclick = share2TextDB;
        document.getElementById('buttonCopyShareURL').onclick = copyShareURL;
    }

    //////////////////
    //              //
    //    Import    //
    //              //
    //////////////////
    // Function that runs when the page is fully loaded
    // This function is used to automatically import the set group combat all
    function onPageLoadForAutoImport() {
        // parse the url for URL parameters
        const urlParams = new URLSearchParams(window.location.search);
        // get url parameter "textdb" if exists
        const textdbID = urlParams.get('textdb');
        // get the import input element
        const importInputElem = document.querySelector(`input#inputSetGroupCombatAll`);
        if (importInputElem == null) {
            return;
        }
        if (textdbID) {
            // Fetch text from textdb.online using the token
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://api.textdb.online/${textdbID}`,
                onload: function(response) {
                    if (response.status === 200) {
                        if (response.responseText) {
                            document.querySelector(`a#group-combat-tab`).click();
                            importInputElem.value = response.responseText;
                            document.querySelector(`button#buttonImportSet`).click();
                            showSuccessMessage('Settings loaded successfully!');
                            clickGetPriceButton();
                        } else {
                            showErrorMessage('No settings found!');
                        }
                    } else {
                        showErrorMessage('Error loading settings!');
                    }
                },
                onerror: function(error) {
                    console.error('Error fetching from textdb.online:', error);
                    showErrorMessage('Error loading settings!');
                }
            });
        }
    }

    // Add event listener for page load
    window.addEventListener('load', onPageLoadForAutoImport);
    // Add Share button
    addShareDialog();
    // Hook alert function
    unsafeWindow.alert = function(msg) {
        console.log("[alert]", msg);
        if (unsafeWindow.isAlertEnabled) {
            showFloatingMessage(msg);
        }
    };

})();