NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name NovelAI auto generator
// @namespace http://tampermonkey.net/
// @version 2.2
// @description nai로 무한 생성해보자.
// @author BK927
// @match https://novelai.net/image
// @icon https://www.google.com/s2/favicons?sz=64&domain=novelai.net
// @grant none
// @license MIT
// @updateURL https://openuserjs.org/meta/BK927/NovelAI_auto_generator.meta.js
// @downloadURL https://openuserjs.org/install/BK927/NovelAI_auto_generator.user.js
// ==/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;
background-color: white;
border: 1px solid black;
padding: 10px;
border-radius: 5px;
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;
}
#autoClickerContainer:hover {
cursor: move;
}
#autoClickerContainer:active {
cursor: move;
}
#autoClickerContainer > * {
margin : 5px;
}
#checkboxContainer {
display: flex;
justify-content: space-around;
}
#checkboxContainer > label > input {
width:25px;
}
#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;
// 드래그 시작 함수
function dragStart(e) {
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
if (dragItem.contains(e.target)) {
active = true;
}
}
// 드래그 중 함수
function drag(e) {
if (active) {
e.preventDefault();
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);
// 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);
}
});
})();