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.

Nainstalovat skript?
Skript doporučený autorem

Mohlo by se vám také líbit Real Profit Calculator.

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

})();