Greasy Fork is available in English.

NovelAI 自动点击与保存

nai生成器.

// ==UserScript==
// @name         NovelAI 自动点击与保存
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  nai生成器.
// @author       BK927 5sigma二次修改
// @match        https://novelai.net/image
// @icon         https://www.google.com/s2/favicons?sz=64&domain=novelai.net
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    // 添加CSS进行造型
    const style = document.createElement('style');
    style.innerHTML = `
        #autoClickerContainer {
            position: fixed;
            display:flex;
            flex-direction: column;
            bottom: 10px;
            right: 10px;
            z-index: 1000;
            border: 1px solid black;
            padding: 10px;
            border-radius: 10px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
            white-space: nowrap;
            -webkit-user-select:none;
            -moz-user-select:none;
            -ms-user-select:none;
            user-select:none;
            font-size: 1rem;
            color: #666;
            backdrop-filter: blur(10px);
            background-color: rgba(255, 255, 255, 0.7);
        }
        #autoClickerContainer:hover {
            cursor: move;
        }
        #autoClickerContainer:active {
            cursor: move;
        }
        #autoClickerContainer > * {
           margin : 5px;
        }
        #checkboxContainer {
            display: flex;
            justify-content: space-around;
        }
        #checkboxContainer > label > input {
            width:1rem;
            appearance: none;
            background-color: #fafafa;
            border: 1px solid #cacece;
            padding: 0.5rem;
            border-radius: 50%;
            display: inline-block;
            position: relative;
        }
        #checkboxContainer > label > input:active,
        #checkboxContainer > label > input:checked:active {
            box-shadow: 0 0 0 2px #ededed, 0 0 0 4px #cacece;
        }
        #checkboxContainer > label > input:checked {
            background-color: #99ee90;
            border: 0.5px solid green;
        }
        #checkboxContainer > label {
            font-size: 1rem;
        }
        #autoClickerCheckbox {
            margin-right: 5px;
        }
        #countdownContainer {

        }
        .inputField {
            margin-left: 10px;
            margin-right: 5px;
            width: 50px;
            padding: 3px;
            border: 1px solid #ccc;
            border-radius: 3px;
            font-size: 0.8em;
        }
    `;

    document.head.appendChild(style);

    // 创建复选框和标签
    const autoClickerContainer = document.createElement('div');
    const checkboxContainer = document.createElement('div');
    checkboxContainer.id = 'checkboxContainer';
    autoClickerContainer.id = 'autoClickerContainer';

    const autoClickLabel = document.createElement('label');
    autoClickLabel.appendChild(document.createTextNode('🔄自动生成'));
    const autoClickInput = document.createElement('input');
    autoClickInput.setAttribute('type', 'checkbox');
    autoClickLabel.appendChild(autoClickInput);

    const autoSaveLabel = document.createElement('label');
    autoSaveLabel.appendChild(document.createTextNode('💾自动保存'));
    const autoSaveInput = document.createElement('input');
    autoSaveInput.setAttribute('type', 'checkbox');
    autoSaveLabel.appendChild(autoSaveInput);

    checkboxContainer.appendChild(autoClickLabel);
    checkboxContainer.appendChild(autoSaveLabel);
    autoClickerContainer.appendChild(checkboxContainer);

    // 创建剩余时间标记
    const countdownContainer = document.createElement('div');
    const countdownText = document.createElement('span');
    countdownContainer.id = 'countdownContainer';
    countdownText.textContent = '剩余时间: 0.0秒';

    countdownContainer.appendChild(countdownText);
    autoClickerContainer.appendChild(countdownContainer);

    const minDelayInput = document.createElement('input');
    minDelayInput.className = 'inputField';
    minDelayInput.type = 'number';
    minDelayInput.min = '0';
    minDelayInput.value = '4'; // Default min delay
    minDelayInput.placeholder = '最小等待时间';

    const maxDelayInput = document.createElement('input');
    maxDelayInput.className = 'inputField';
    maxDelayInput.type = 'number';
    maxDelayInput.min = '0';
    maxDelayInput.value = '8'; // Default max delay
    maxDelayInput.placeholder = '最大等待时间';

    countdownContainer.appendChild(minDelayInput);
    countdownContainer.appendChild(maxDelayInput);

    document.body.appendChild(autoClickerContainer);

    let autoClickIntervalId;
    let countdownIntervalId; // 倒计时间隔的ID
    let countdown; // 剩余时间(秒)
    let scheduledFlag = false;
    let imgSavedFlag = false; // 检查是否保存了图像

    const dragItem = document.getElementById('autoClickerContainer');
    let active = false;
    let currentX;
    let currentY;
    let initialX;
    let initialY;
    let xOffset = 0;
    let yOffset = 0;

    // 创建一个新的隐藏/显示按钮
    const toggleButton = document.createElement('button');
    toggleButton.textContent = '隐藏/显示';
    toggleButton.style.borderRadius = '5px'; // 按钮圆角
    toggleButton.style.backgroundColor = '#007aff'; // 按钮背景颜色
    toggleButton.style.color = 'white'; // 按钮文字颜色
    toggleButton.style.border = 'none'; // 去掉按钮边框
    toggleButton.style.padding = '5px 10px'; // 按钮内边距
    autoClickerContainer.appendChild(toggleButton);

    // 按钮点击事件,用于切换容器的可见性
    toggleButton.addEventListener('click', () => {
        const children = autoClickerContainer.children;
        for (let i = 0; i < children.length; i++) {
            if (children[i] !== toggleButton) {
                children[i].style.display = children[i].style.display === 'none' ? 'block' : 'none';
            }
        }
    });

    // 创建一个新的元素来显示信息
    const authorLabel = document.createElement('div');
    authorLabel.style.position = 'absolute';
    authorLabel.style.right = '10px';
    authorLabel.style.bottom = '10px';
    authorLabel.style.fontSize = '0.8em';
    authorLabel.textContent = '5sigma ver2.0';

    // 将我的标签添加到容器中
    autoClickerContainer.appendChild(authorLabel);

    // 拖动启动函数
    function dragStart(e) {
        if (e.type === "touchstart") {
            initialX = e.touches[0].clientX - xOffset;
            initialY = e.touches[0].clientY - yOffset;
        } else {
            initialX = e.clientX - xOffset;
            initialY = e.clientY - yOffset;
        }

        if (dragItem.contains(e.target)) {
            active = true;
        }
    }

    // 正在拖动函数
    function drag(e) {
        if (active) {
            e.preventDefault();

            if (e.type === "touchmove") {
                currentX = e.touches[0].clientX - initialX;
                currentY = e.touches[0].clientY - initialY;
            } else {
                currentX = e.clientX - initialX;
                currentY = e.clientY - initialY;
            }

            xOffset = currentX;
            yOffset = currentY;

            setTranslate(currentX, currentY, dragItem);
        }
    }

    // 拖动结束函数
    function dragEnd() {
        initialX = currentX;
        initialY = currentY;

        active = false;
    }

    minDelayInput.addEventListener('change', () => {
        const minDelay = parseFloat(minDelayInput.value);
        const maxDelay = parseFloat(maxDelayInput.value);

        if (minDelay > maxDelay) {
            maxDelayInput.value = minDelay;
        }
    });

    // 位置设置函数
    function setTranslate(xPos, yPos, el) {
        el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
    }

    // 添加事件侦听器
    dragItem.addEventListener("mousedown", dragStart, false);
    document.addEventListener("mouseup", dragEnd, false);
    document.addEventListener("mousemove", drag, false);

    // 添加触摸事件监听器
    dragItem.addEventListener("touchstart", dragStart, false);
    document.addEventListener("touchend", dragEnd, false);
    document.addEventListener("touchmove", drag, false);

    // 使用XPath选择按钮的函数
    function getElementByXPath(xpath) {
        const result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return result.singleNodeValue;
    }

    // 按钮点击函数
    function clickButton() {
        const xpath = '//*[@id="__next"]/div[2]/div[4]/div[1]/div[5]/button';
        const button = getElementByXPath(xpath);
        if (button && !button.disabled && autoClickInput.checked) {
            button.click();
            scheduledFlag = false;
        }
    }

    // 自动单击超时函数
    function scheduleNextClick(delay) {
        countdown = delay / 1000;
        clearInterval(countdownIntervalId);
        countdownIntervalId = setInterval(updateCountdownDisplay, 100); // 0.1每秒更新
        setTimeout(() => {
            imgSavedFlag = false;
            clickButton();}, delay);
    }

    // 显示剩余时间的函数
    function updateCountdownDisplay() {
        countdown -= 0.1;
        if (countdown < 0) {
            clearInterval(countdownIntervalId);
            countdown = 0;
        }
        countdownText.textContent = `剩余时间: ${countdown.toFixed(1)}秒`;
    }

    // 自动点击事件侦听器
    autoClickInput.addEventListener('change', () => {
        const button = getElementByXPath('//*[@id="__next"]/div[2]/div[4]/div[1]/div[5]/button');
        if (autoClickInput.checked && button != null) {
            clickButton(); // 运行第一次单击
            // 间隔设置
            autoClickIntervalId = setInterval(() => {
                if (autoClickInput.checked && !button.disabled && !scheduledFlag && maxDelayInput.value !== '' && minDelayInput.value !== '') {
                    scheduledFlag = true;
                    const delay = Math.random() * parseFloat(maxDelayInput.value) * 1000 + parseFloat(minDelayInput.value) * 1000; // 随机延迟
                    scheduleNextClick(delay); // 开始下一次点击计划和倒计时
                }

                if(autoSaveInput.checked && !button.disabled && !imgSavedFlag){
                    const saveButton = getElementByXPath('//*[@id="__next"]/div[2]/div[4]/div[2]/div[2]/div[3]/div/div[3]/div/div[3]/button');
                    if(saveButton != null){
                        saveButton.click();
                        imgSavedFlag = true;
                    }
                }
            }, 500); // 0.5每秒重复
        }

        if(!autoClickInput.checked){
            clearInterval(autoClickIntervalId);
        }
    });

    // 检测暗夜模式
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
        // 用户的操作系统处于暗夜模式
        autoClickerContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
        autoClickerContainer.style.color = 'white';
    } else {
        // 用户的操作系统处于明亮模式
        autoClickerContainer.style.color = 'black';
    }

    // 监听颜色方案的改变
    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
        if (e.matches) {
            // 用户的操作系统切换到了暗夜模式
            autoClickerContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
            autoClickerContainer.style.color = 'white';
        } else {
            // 用户的操作系统切换到了明亮模式
            autoClickerContainer.style.backgroundColor = 'rgba(255, 255, 255, 0.7)';
            autoClickerContainer.style.color = 'black';
        }
    });
})();